netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH iwl-next v9 0/7] ixgbe: Add support for Intel(R) E610 device
@ 2024-10-03 14:16 Piotr Kwapulinski
  2024-10-03 14:16 ` [PATCH iwl-next v9 1/7] ixgbe: Add support for E610 FW Admin Command Interface Piotr Kwapulinski
                   ` (6 more replies)
  0 siblings, 7 replies; 16+ messages in thread
From: Piotr Kwapulinski @ 2024-10-03 14:16 UTC (permalink / raw)
  To: intel-wired-lan; +Cc: netdev, Piotr Kwapulinski

Add initial support for Intel(R) E610 Series of network devices. The E610
is based on X550 but adds firmware managed link, enhanced security
capabilities and support for updated server manageability.

This patch series adds low level support for the following features and
enables link management.

Piotr Kwapulinski (7):
  ixgbe: Add support for E610 FW Admin Command Interface
  ixgbe: Add support for E610 device capabilities detection
  ixgbe: Add link management support for E610 device
  ixgbe: Add support for NVM handling in E610 device
  ixgbe: Add ixgbe_x540 multiple header inclusion protection
  ixgbe: Clean up the E610 link management related code
  ixgbe: Enable link management in E610 device

 drivers/net/ethernet/intel/ixgbe/Makefile     |    4 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe.h      |   14 +-
 .../net/ethernet/intel/ixgbe/ixgbe_82599.c    |    3 +-
 .../net/ethernet/intel/ixgbe/ixgbe_common.c   |   25 +-
 .../net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c   |    3 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 2579 +++++++++++++++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h |   76 +
 .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c  |    6 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c  |    3 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |  437 ++-
 drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c  |    4 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c  |    5 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_type.h |   72 +-
 .../ethernet/intel/ixgbe/ixgbe_type_e610.h    | 1067 +++++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c |   12 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_x540.h |    7 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c |   29 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_x550.h |   20 +
 18 files changed, 4318 insertions(+), 48 deletions(-)
 create mode 100644 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
 create mode 100644 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
 create mode 100644 drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
 create mode 100644 drivers/net/ethernet/intel/ixgbe/ixgbe_x550.h

-- 
V1 -> V2:
  - fix for no previous prototypes for ixgbe_set_fw_drv_ver_x550,
    ixgbe_set_ethertype_anti_spoofing_x550 and
    ixgbe_set_source_address_pruning_x550
  - fix variable type mismatch: u16, u32, u64
  - fix inaccurate doc for ixgbe_aci_desc
  - remove extra buffer allocation in ixgbe_aci_send_cmd_execute
  - replace custom loops with generic fls64 in ixgbe_get_media_type_e610
  - add buffer caching and optimization in ixgbe_aci_send_cmd
V2 -> V3:
  - revert ixgbe_set_eee_capable inlining
  - update copyright date
V3 -> V4:
  - cleanup local variables in ixgbe_get_num_per_func
  - remove redundant casting in ixgbe_aci_disable_rxen
V4 -> V5:
  - remove unnecessary structure members initialization
  - remove unnecessary casting
  - fix comments
V5 -> V6:
  - create dedicated patch for ixgbe_x540 multiple header inclusion protection
  - extend debug messages
  - add descriptive constant for Receive Address Registers
  - remove unrelated changes
  - create dedicated patch for code cleanup
  - remove and cleanup of some conditions
  - spelling fixes
V6 -> V7:
  - rebase to adopt recent Makefile "ixgbe-y" changes
V7 -> V8:
  - implement more clear execution flow in ixgbe_aci_list_caps(),
    ixgbe_discover_func_caps(), ixgbe_get_link_status(),
    ixgbe_fc_autoneg_e610(), ixgbe_disable_rx_e610() and
    ixgbe_setup_phy_link_e610()
  - make use of FIELD_PREP macro in ixgbe_is_media_cage_present()
V8 -> V9:
  - tune-up auto-negotiation advertised link speeds at driver load
  - update the method of pending events detection
  - update the way of discovering device and function capabilities
  - update the parameter set-up for the firmware-controlled PHYs
  - fix port down after driver reload

2.43.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH iwl-next v9 1/7] ixgbe: Add support for E610 FW Admin Command Interface
  2024-10-03 14:16 [PATCH iwl-next v9 0/7] ixgbe: Add support for Intel(R) E610 device Piotr Kwapulinski
@ 2024-10-03 14:16 ` Piotr Kwapulinski
  2024-10-03 14:16 ` [PATCH iwl-next v9 2/7] ixgbe: Add support for E610 device capabilities detection Piotr Kwapulinski
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 16+ messages in thread
From: Piotr Kwapulinski @ 2024-10-03 14:16 UTC (permalink / raw)
  To: intel-wired-lan
  Cc: netdev, Piotr Kwapulinski, Stefan Wegrzyn, Jedrzej Jagielski,
	Michal Swiatkowski, Simon Horman

Add low level support for Admin Command Interface (ACI). ACI is the
Firmware interface used by a driver to communicate with E610 adapter. Add
the following ACI features:
- data structures, macros, register definitions
- commands handling
- events handling

Co-developed-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
Signed-off-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
Co-developed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Signed-off-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Reviewed-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/Makefile     |    4 +-
 .../net/ethernet/intel/ixgbe/ixgbe_common.c   |    6 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c |  495 ++++++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h |   19 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_type.h |   72 +-
 .../ethernet/intel/ixgbe/ixgbe_type_e610.h    | 1066 +++++++++++++++++
 6 files changed, 1655 insertions(+), 7 deletions(-)
 create mode 100644 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
 create mode 100644 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
 create mode 100644 drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h

diff --git a/drivers/net/ethernet/intel/ixgbe/Makefile b/drivers/net/ethernet/intel/ixgbe/Makefile
index 965e5ce..b456d10 100644
--- a/drivers/net/ethernet/intel/ixgbe/Makefile
+++ b/drivers/net/ethernet/intel/ixgbe/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
-# Copyright(c) 1999 - 2018 Intel Corporation.
+# Copyright(c) 1999 - 2024 Intel Corporation.
 #
 # Makefile for the Intel(R) 10GbE PCI Express ethernet driver
 #
@@ -9,7 +9,7 @@ obj-$(CONFIG_IXGBE) += ixgbe.o
 ixgbe-y := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \
            ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o ixgbe_sriov.o \
            ixgbe_mbx.o ixgbe_x540.o ixgbe_x550.o ixgbe_lib.o ixgbe_ptp.o \
-           ixgbe_xsk.o
+           ixgbe_xsk.o ixgbe_e610.o
 
 ixgbe-$(CONFIG_IXGBE_DCB) +=  ixgbe_dcb.o ixgbe_dcb_82598.o \
                               ixgbe_dcb_82599.o ixgbe_dcb_nl.o
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
index 3be1bfb..bfab2c0 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
@@ -660,7 +660,11 @@ int ixgbe_get_bus_info_generic(struct ixgbe_hw *hw)
 	hw->bus.type = ixgbe_bus_type_pci_express;
 
 	/* Get the negotiated link width and speed from PCI config space */
-	link_status = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_LINK_STATUS);
+	if (hw->mac.type == ixgbe_mac_e610)
+		link_status = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_LINK_STATUS_E610);
+	else
+		link_status = ixgbe_read_pci_cfg_word(hw,
+						      IXGBE_PCI_LINK_STATUS);
 
 	hw->bus.width = ixgbe_convert_bus_width(link_status);
 	hw->bus.speed = ixgbe_convert_bus_speed(link_status);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
new file mode 100644
index 0000000..28bd7da
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
@@ -0,0 +1,495 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2024 Intel Corporation. */
+
+#include "ixgbe_common.h"
+#include "ixgbe_e610.h"
+#include "ixgbe_type.h"
+#include "ixgbe_x540.h"
+#include "ixgbe_phy.h"
+
+/**
+ * ixgbe_should_retry_aci_send_cmd_execute - decide if ACI command should
+ * be resent
+ * @opcode: ACI opcode
+ *
+ * Check if ACI command should be sent again depending on the provided opcode.
+ * It may happen when CSR is busy during link state changes.
+ *
+ * Return: true if the sending command routine should be repeated,
+ * otherwise false.
+ */
+static bool ixgbe_should_retry_aci_send_cmd_execute(u16 opcode)
+{
+	switch (opcode) {
+	case ixgbe_aci_opc_disable_rxen:
+	case ixgbe_aci_opc_get_phy_caps:
+	case ixgbe_aci_opc_get_link_status:
+	case ixgbe_aci_opc_get_link_topo:
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * ixgbe_aci_send_cmd_execute - execute sending FW Admin Command to FW Admin
+ * Command Interface
+ * @hw: pointer to the HW struct
+ * @desc: descriptor describing the command
+ * @buf: buffer to use for indirect commands (NULL for direct commands)
+ * @buf_size: size of buffer for indirect commands (0 for direct commands)
+ *
+ * Admin Command is sent using CSR by setting descriptor and buffer in specific
+ * registers.
+ *
+ * Return: the exit code of the operation.
+ * * - 0 - success.
+ * * - -EIO - CSR mechanism is not enabled.
+ * * - -EBUSY - CSR mechanism is busy.
+ * * - -EINVAL - buf_size is too big or
+ * invalid argument buf or buf_size.
+ * * - -ETIME - Admin Command X command timeout.
+ * * - -EIO - Admin Command X invalid state of HICR register or
+ * Admin Command failed because of bad opcode was returned or
+ * Admin Command failed with error Y.
+ */
+static int ixgbe_aci_send_cmd_execute(struct ixgbe_hw *hw,
+				      struct ixgbe_aci_desc *desc,
+				      void *buf, u16 buf_size)
+{
+	u16 opcode, buf_tail_size = buf_size % 4;
+	u32 *raw_desc = (u32 *)desc;
+	u32 hicr, i, buf_tail = 0;
+	bool valid_buf = false;
+
+	hw->aci.last_status = IXGBE_ACI_RC_OK;
+
+	/* It's necessary to check if mechanism is enabled */
+	hicr = IXGBE_READ_REG(hw, IXGBE_PF_HICR);
+
+	if (!(hicr & IXGBE_PF_HICR_EN))
+		return -EIO;
+
+	if (hicr & IXGBE_PF_HICR_C) {
+		hw->aci.last_status = IXGBE_ACI_RC_EBUSY;
+		return -EBUSY;
+	}
+
+	opcode = desc->opcode;
+
+	if (buf_size > IXGBE_ACI_MAX_BUFFER_SIZE)
+		return -EINVAL;
+
+	if (buf)
+		desc->flags |= IXGBE_ACI_FLAG_BUF;
+
+	if (desc->flags & IXGBE_ACI_FLAG_BUF) {
+		if ((buf && !buf_size) ||
+		    (!buf && buf_size))
+			return -EINVAL;
+		if (buf && buf_size)
+			valid_buf = true;
+	}
+
+	if (valid_buf) {
+		if (buf_tail_size)
+			memcpy(&buf_tail, buf + buf_size - buf_tail_size,
+			       buf_tail_size);
+
+		if (((buf_size + 3) & ~0x3) > IXGBE_ACI_LG_BUF)
+			desc->flags |= IXGBE_ACI_FLAG_LB;
+
+		desc->datalen = buf_size;
+
+		if (desc->flags & IXGBE_ACI_FLAG_RD) {
+			for (i = 0; i < buf_size / 4; i++)
+				IXGBE_WRITE_REG(hw, IXGBE_PF_HIBA(i), ((u32 *)buf)[i]);
+			if (buf_tail_size)
+				IXGBE_WRITE_REG(hw, IXGBE_PF_HIBA(i), buf_tail);
+		}
+	}
+
+	/* Descriptor is written to specific registers */
+	for (i = 0; i < IXGBE_ACI_DESC_SIZE_IN_DWORDS; i++)
+		IXGBE_WRITE_REG(hw, IXGBE_PF_HIDA(i), raw_desc[i]);
+
+	/* SW has to set PF_HICR.C bit and clear PF_HICR.SV and
+	 * PF_HICR_EV
+	 */
+	hicr = (IXGBE_READ_REG(hw, IXGBE_PF_HICR) | IXGBE_PF_HICR_C) &
+	       ~(IXGBE_PF_HICR_SV | IXGBE_PF_HICR_EV);
+	IXGBE_WRITE_REG(hw, IXGBE_PF_HICR, hicr);
+
+#define MAX_SLEEP_RESP_US 1000
+#define MAX_TMOUT_RESP_SYNC_US 100000000
+
+	/* Wait for sync Admin Command response */
+	read_poll_timeout(IXGBE_READ_REG, hicr,
+			  (hicr & IXGBE_PF_HICR_SV) ||
+			  !(hicr & IXGBE_PF_HICR_C),
+			  MAX_SLEEP_RESP_US, MAX_TMOUT_RESP_SYNC_US, true, hw,
+			  IXGBE_PF_HICR);
+
+#define MAX_TMOUT_RESP_ASYNC_US 150000000
+
+	/* Wait for async Admin Command response */
+	read_poll_timeout(IXGBE_READ_REG, hicr,
+			  (hicr & IXGBE_PF_HICR_EV) ||
+			  !(hicr & IXGBE_PF_HICR_C),
+			  MAX_SLEEP_RESP_US, MAX_TMOUT_RESP_ASYNC_US, true, hw,
+			  IXGBE_PF_HICR);
+
+	/* Read sync Admin Command response */
+	if ((hicr & IXGBE_PF_HICR_SV)) {
+		for (i = 0; i < IXGBE_ACI_DESC_SIZE_IN_DWORDS; i++) {
+			raw_desc[i] = IXGBE_READ_REG(hw, IXGBE_PF_HIDA(i));
+			raw_desc[i] = raw_desc[i];
+		}
+	}
+
+	/* Read async Admin Command response */
+	if ((hicr & IXGBE_PF_HICR_EV) && !(hicr & IXGBE_PF_HICR_C)) {
+		for (i = 0; i < IXGBE_ACI_DESC_SIZE_IN_DWORDS; i++) {
+			raw_desc[i] = IXGBE_READ_REG(hw, IXGBE_PF_HIDA_2(i));
+			raw_desc[i] = raw_desc[i];
+		}
+	}
+
+	/* Handle timeout and invalid state of HICR register */
+	if (hicr & IXGBE_PF_HICR_C)
+		return -ETIME;
+
+	if (!(hicr & IXGBE_PF_HICR_SV) && !(hicr & IXGBE_PF_HICR_EV))
+		return -EIO;
+
+	/* For every command other than 0x0014 treat opcode mismatch
+	 * as an error. Response to 0x0014 command read from HIDA_2
+	 * is a descriptor of an event which is expected to contain
+	 * different opcode than the command.
+	 */
+	if (desc->opcode != opcode &&
+	    opcode != ixgbe_aci_opc_get_fw_event)
+		return -EIO;
+
+	if (desc->retval) {
+		hw->aci.last_status = (enum ixgbe_aci_err)desc->retval;
+		return -EIO;
+	}
+
+	/* Write a response values to a buf */
+	if (valid_buf) {
+		for (i = 0; i < buf_size / 4; i++)
+			((u32 *)buf)[i] = IXGBE_READ_REG(hw, IXGBE_PF_HIBA(i));
+		if (buf_tail_size) {
+			buf_tail = IXGBE_READ_REG(hw, IXGBE_PF_HIBA(i));
+			memcpy(buf + buf_size - buf_tail_size, &buf_tail,
+			       buf_tail_size);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * ixgbe_aci_send_cmd - send FW Admin Command to FW Admin Command Interface
+ * @hw: pointer to the HW struct
+ * @desc: descriptor describing the command
+ * @buf: buffer to use for indirect commands (NULL for direct commands)
+ * @buf_size: size of buffer for indirect commands (0 for direct commands)
+ *
+ * Helper function to send FW Admin Commands to the FW Admin Command Interface.
+ *
+ * Retry sending the FW Admin Command multiple times to the FW ACI
+ * if the EBUSY Admin Command error is returned.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_aci_send_cmd(struct ixgbe_hw *hw, struct ixgbe_aci_desc *desc,
+		       void *buf, u16 buf_size)
+{
+	u8 idx = 0, *buf_cpy __free(kfree) = NULL;
+	struct ixgbe_aci_desc desc_cpy;
+	enum ixgbe_aci_err last_status;
+	u16 opcode = desc->opcode;
+	bool is_cmd_for_retry;
+	unsigned long timeout;
+	int err;
+
+	is_cmd_for_retry = ixgbe_should_retry_aci_send_cmd_execute(opcode);
+
+	if (is_cmd_for_retry) {
+		if (buf) {
+			buf_cpy = kmalloc(buf_size, GFP_KERNEL);
+			if (!buf_cpy)
+				return -ENOMEM;
+			*buf_cpy = *(u8 *)buf;
+		}
+		desc_cpy = *desc;
+	}
+
+	timeout = jiffies + msecs_to_jiffies(IXGBE_ACI_SEND_TIMEOUT_MS);
+	do {
+		mutex_lock(&hw->aci.lock);
+		err = ixgbe_aci_send_cmd_execute(hw, desc, buf, buf_size);
+		last_status = hw->aci.last_status;
+		mutex_unlock(&hw->aci.lock);
+
+		if (!is_cmd_for_retry || !err ||
+		    last_status != IXGBE_ACI_RC_EBUSY)
+			break;
+
+		if (buf)
+			memcpy(buf, buf_cpy, buf_size);
+		*desc = desc_cpy;
+
+		msleep(IXGBE_ACI_SEND_DELAY_TIME_MS);
+	} while (++idx < IXGBE_ACI_SEND_MAX_EXECUTE &&
+		 time_before(jiffies, timeout));
+
+	return err;
+}
+
+/**
+ * ixgbe_aci_check_event_pending - check if there are any pending events
+ * @hw: pointer to the HW struct
+ *
+ * Determine if there are any pending events.
+ *
+ * Return: true if there are any currently pending events
+ * otherwise false.
+ */
+bool ixgbe_aci_check_event_pending(struct ixgbe_hw *hw)
+{
+	u32 ep_bit_mask = hw->bus.func ? GL_FWSTS_EP_PF1 : GL_FWSTS_EP_PF0;
+	u32 fwsts = IXGBE_READ_REG(hw, GL_FWSTS);
+
+	return (fwsts & ep_bit_mask) ? true : false;
+}
+
+/**
+ * ixgbe_aci_get_event - get an event from ACI
+ * @hw: pointer to the HW struct
+ * @e: event information structure
+ * @pending: optional flag signaling that there are more pending events
+ *
+ * Obtain an event from ACI and return its content
+ * through 'e' using ACI command (0x0014).
+ * Provide information if there are more events
+ * to retrieve through 'pending'.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_aci_get_event(struct ixgbe_hw *hw, struct ixgbe_aci_event *e,
+			bool *pending)
+{
+	struct ixgbe_aci_desc desc;
+	int err;
+
+	if (!e || (!e->msg_buf && e->buf_len))
+		return -EINVAL;
+
+	mutex_lock(&hw->aci.lock);
+
+	/* Check if there are any events pending */
+	if (!ixgbe_aci_check_event_pending(hw)) {
+		err = -ENOENT;
+		goto aci_get_event_exit;
+	}
+
+	/* Obtain pending event */
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_fw_event);
+	err = ixgbe_aci_send_cmd_execute(hw, &desc, e->msg_buf, e->buf_len);
+	if (err)
+		goto aci_get_event_exit;
+
+	/* Returned 0x0014 opcode indicates that no event was obtained */
+	if (desc.opcode == ixgbe_aci_opc_get_fw_event) {
+		err = -ENOENT;
+		goto aci_get_event_exit;
+	}
+
+	/* Determine size of event data */
+	e->msg_len = min_t(u16, desc.datalen, e->buf_len);
+	/* Write event descriptor to event info structure */
+	memcpy(&e->desc, &desc, sizeof(e->desc));
+
+	/* Check if there are any further events pending */
+	if (pending)
+		*pending = ixgbe_aci_check_event_pending(hw);
+
+aci_get_event_exit:
+	mutex_unlock(&hw->aci.lock);
+
+	return err;
+}
+
+/**
+ * ixgbe_fill_dflt_direct_cmd_desc - fill ACI descriptor with default values.
+ * @desc: pointer to the temp descriptor (non DMA mem)
+ * @opcode: the opcode can be used to decide which flags to turn off or on
+ *
+ * Helper function to fill the descriptor desc with default values
+ * and the provided opcode.
+ */
+void ixgbe_fill_dflt_direct_cmd_desc(struct ixgbe_aci_desc *desc, u16 opcode)
+{
+	/* Zero out the desc. */
+	memset(desc, 0, sizeof(*desc));
+	desc->opcode = opcode;
+	desc->flags = IXGBE_ACI_FLAG_SI;
+}
+
+/**
+ * ixgbe_aci_req_res - request a common resource
+ * @hw: pointer to the HW struct
+ * @res: resource ID
+ * @access: access type
+ * @sdp_number: resource number
+ * @timeout: the maximum time in ms that the driver may hold the resource
+ *
+ * Requests a common resource using the ACI command (0x0008).
+ * Specifies the maximum time the driver may hold the resource.
+ * If the requested resource is currently occupied by some other driver,
+ * a busy return value is returned and the timeout field value indicates the
+ * maximum time the current owner has to free it.
+ *
+ * Return: the exit code of the operation.
+ */
+static int ixgbe_aci_req_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res,
+			     enum ixgbe_aci_res_access_type access,
+			     u8 sdp_number, u32 *timeout)
+{
+	struct ixgbe_aci_cmd_req_res *cmd_resp;
+	struct ixgbe_aci_desc desc;
+	int err;
+
+	cmd_resp = &desc.params.res_owner;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_req_res);
+
+	cmd_resp->res_id = res;
+	cmd_resp->access_type = access;
+	cmd_resp->res_number = sdp_number;
+	cmd_resp->timeout = *timeout;
+	*timeout = 0;
+
+	err = ixgbe_aci_send_cmd(hw, &desc, NULL, 0);
+
+	/* If the resource is held by some other driver, the command completes
+	 * with a busy return value and the timeout field indicates the maximum
+	 * time the current owner of the resource has to free it.
+	 */
+	if (!err || hw->aci.last_status == IXGBE_ACI_RC_EBUSY)
+		*timeout = cmd_resp->timeout;
+
+	return err;
+}
+
+/**
+ * ixgbe_aci_release_res - release a common resource using ACI
+ * @hw: pointer to the HW struct
+ * @res: resource ID
+ * @sdp_number: resource number
+ *
+ * Release a common resource using ACI command (0x0009).
+ *
+ * Return: the exit code of the operation.
+ */
+static int ixgbe_aci_release_res(struct ixgbe_hw *hw,
+				 enum ixgbe_aci_res_ids res, u8 sdp_number)
+{
+	struct ixgbe_aci_cmd_req_res *cmd;
+	struct ixgbe_aci_desc desc;
+
+	cmd = &desc.params.res_owner;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_release_res);
+
+	cmd->res_id = res;
+	cmd->res_number = sdp_number;
+
+	return ixgbe_aci_send_cmd(hw, &desc, NULL, 0);
+}
+
+/**
+ * ixgbe_acquire_res - acquire the ownership of a resource
+ * @hw: pointer to the HW structure
+ * @res: resource ID
+ * @access: access type (read or write)
+ * @timeout: timeout in milliseconds
+ *
+ * Make an attempt to acquire the ownership of a resource using
+ * the ixgbe_aci_req_res to utilize ACI.
+ * In case if some other driver has previously acquired the resource and
+ * performed any necessary updates, the -EALREADY is returned,
+ * and the caller does not obtain the resource and has no further work to do.
+ * If needed, the function will poll until the current lock owner timeouts.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_acquire_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res,
+		      enum ixgbe_aci_res_access_type access, u32 timeout)
+{
+#define IXGBE_RES_POLLING_DELAY_MS	10
+	u32 delay = IXGBE_RES_POLLING_DELAY_MS;
+	u32 res_timeout = timeout;
+	u32 retry_timeout;
+	int err;
+
+	err = ixgbe_aci_req_res(hw, res, access, 0, &res_timeout);
+
+	/* A return code of -EALREADY means that another driver has
+	 * previously acquired the resource and performed any necessary updates;
+	 * in this case the caller does not obtain the resource and has no
+	 * further work to do.
+	 */
+	if (err == -EALREADY)
+		return err;
+
+	/* If necessary, poll until the current lock owner timeouts.
+	 * Set retry_timeout to the timeout value reported by the FW in the
+	 * response to the "Request Resource Ownership" (0x0008) Admin Command
+	 * as it indicates the maximum time the current owner of the resource
+	 * is allowed to hold it.
+	 */
+	retry_timeout = res_timeout;
+	while (err && retry_timeout && res_timeout) {
+		msleep(delay);
+		retry_timeout = (retry_timeout > delay) ?
+			retry_timeout - delay : 0;
+		err = ixgbe_aci_req_res(hw, res, access, 0, &res_timeout);
+
+		/* Success - lock acquired.
+		 * -EALREADY - lock free, no work to do.
+		 */
+		if (!err || err == -EALREADY)
+			break;
+	}
+
+	return err;
+}
+
+/**
+ * ixgbe_release_res - release a common resource
+ * @hw: pointer to the HW structure
+ * @res: resource ID
+ *
+ * Release a common resource using ixgbe_aci_release_res.
+ */
+void ixgbe_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res)
+{
+	u32 total_delay = 0;
+	int err;
+
+	err = ixgbe_aci_release_res(hw, res, 0);
+
+	/* There are some rare cases when trying to release the resource
+	 * results in an admin command timeout, so handle them correctly.
+	 */
+	while (err == -ETIME &&
+	       total_delay < IXGBE_ACI_RELEASE_RES_TIMEOUT) {
+		usleep_range(1000, 1500);
+		err = ixgbe_aci_release_res(hw, res, 0);
+		total_delay++;
+	}
+}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
new file mode 100644
index 0000000..18b831b
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Intel Corporation. */
+
+#ifndef _IXGBE_E610_H_
+#define _IXGBE_E610_H_
+
+#include "ixgbe_type.h"
+
+int ixgbe_aci_send_cmd(struct ixgbe_hw *hw, struct ixgbe_aci_desc *desc,
+		       void *buf, u16 buf_size);
+bool ixgbe_aci_check_event_pending(struct ixgbe_hw *hw);
+int ixgbe_aci_get_event(struct ixgbe_hw *hw, struct ixgbe_aci_event *e,
+			bool *pending);
+void ixgbe_fill_dflt_direct_cmd_desc(struct ixgbe_aci_desc *desc, u16 opcode);
+int ixgbe_acquire_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res,
+		      enum ixgbe_aci_res_access_type access, u32 timeout);
+void ixgbe_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res);
+
+#endif /* _IXGBE_E610_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index 346e3d9..4188b8c 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright(c) 1999 - 2018 Intel Corporation. */
+/* Copyright(c) 1999 - 2024 Intel Corporation. */
 
 #ifndef _IXGBE_TYPE_H_
 #define _IXGBE_TYPE_H_
@@ -7,6 +7,7 @@
 #include <linux/types.h>
 #include <linux/mdio.h>
 #include <linux/netdevice.h>
+#include "ixgbe_type_e610.h"
 
 /* Device IDs */
 #define IXGBE_DEV_ID_82598               0x10B6
@@ -71,12 +72,19 @@
 #define IXGBE_DEV_ID_X550EM_A_1G_T	0x15E4
 #define IXGBE_DEV_ID_X550EM_A_1G_T_L	0x15E5
 
+#define IXGBE_DEV_ID_E610_BACKPLANE	0x57AE
+#define IXGBE_DEV_ID_E610_SFP		0x57AF
+#define IXGBE_DEV_ID_E610_10G_T		0x57B0
+#define IXGBE_DEV_ID_E610_2_5G_T	0x57B1
+#define IXGBE_DEV_ID_E610_SGMII		0x57B2
+
 /* VF Device IDs */
 #define IXGBE_DEV_ID_82599_VF		0x10ED
 #define IXGBE_DEV_ID_X540_VF		0x1515
 #define IXGBE_DEV_ID_X550_VF		0x1565
 #define IXGBE_DEV_ID_X550EM_X_VF	0x15A8
 #define IXGBE_DEV_ID_X550EM_A_VF	0x15C5
+#define IXGBE_DEV_ID_E610_VF		0x57AD
 
 #define IXGBE_CAT(r, m)	IXGBE_##r##_##m
 
@@ -1600,7 +1608,7 @@ enum {
 #define IXGBE_EICR_PCI          0x00040000 /* PCI Exception */
 #define IXGBE_EICR_MAILBOX      0x00080000 /* VF to PF Mailbox Interrupt */
 #define IXGBE_EICR_LSC          0x00100000 /* Link Status Change */
-#define IXGBE_EICR_LINKSEC      0x00200000 /* PN Threshold */
+#define IXGBE_EICR_FW_EVENT	0x00200000 /* Async FW event */
 #define IXGBE_EICR_MNG          0x00400000 /* Manageability Event Interrupt */
 #define IXGBE_EICR_TS           0x00800000 /* Thermal Sensor Event */
 #define IXGBE_EICR_TIMESYNC     0x01000000 /* Timesync Event */
@@ -1636,6 +1644,7 @@ enum {
 #define IXGBE_EICS_PCI          IXGBE_EICR_PCI       /* PCI Exception */
 #define IXGBE_EICS_MAILBOX      IXGBE_EICR_MAILBOX   /* VF to PF Mailbox Int */
 #define IXGBE_EICS_LSC          IXGBE_EICR_LSC       /* Link Status Change */
+#define IXGBE_EICS_FW_EVENT	IXGBE_EICR_FW_EVENT  /* Async FW event */
 #define IXGBE_EICS_MNG          IXGBE_EICR_MNG       /* MNG Event Interrupt */
 #define IXGBE_EICS_TIMESYNC     IXGBE_EICR_TIMESYNC  /* Timesync Event */
 #define IXGBE_EICS_GPI_SDP0(_hw)	IXGBE_EICR_GPI_SDP0(_hw)
@@ -1654,6 +1663,7 @@ enum {
 #define IXGBE_EIMS_PCI          IXGBE_EICR_PCI       /* PCI Exception */
 #define IXGBE_EIMS_MAILBOX      IXGBE_EICR_MAILBOX   /* VF to PF Mailbox Int */
 #define IXGBE_EIMS_LSC          IXGBE_EICR_LSC       /* Link Status Change */
+#define IXGBE_EIMS_FW_EVENT	IXGBE_EICR_FW_EVENT  /* Async FW event */
 #define IXGBE_EIMS_MNG          IXGBE_EICR_MNG       /* MNG Event Interrupt */
 #define IXGBE_EIMS_TS           IXGBE_EICR_TS        /* Thermel Sensor Event */
 #define IXGBE_EIMS_TIMESYNC     IXGBE_EICR_TIMESYNC  /* Timesync Event */
@@ -1673,6 +1683,7 @@ enum {
 #define IXGBE_EIMC_PCI          IXGBE_EICR_PCI       /* PCI Exception */
 #define IXGBE_EIMC_MAILBOX      IXGBE_EICR_MAILBOX   /* VF to PF Mailbox Int */
 #define IXGBE_EIMC_LSC          IXGBE_EICR_LSC       /* Link Status Change */
+#define IXGBE_EIMC_FW_EVENT	IXGBE_EICR_FW_EVENT  /* Async FW event */
 #define IXGBE_EIMC_MNG          IXGBE_EICR_MNG       /* MNG Event Interrupt */
 #define IXGBE_EIMC_TIMESYNC     IXGBE_EICR_TIMESYNC  /* Timesync Event */
 #define IXGBE_EIMC_GPI_SDP0(_hw)	IXGBE_EICR_GPI_SDP0(_hw)
@@ -2068,6 +2079,7 @@ enum {
 #define IXGBE_SAN_MAC_ADDR_PTR  0x28
 #define IXGBE_DEVICE_CAPS       0x2C
 #define IXGBE_SERIAL_NUMBER_MAC_ADDR 0x11
+#define IXGBE_PCIE_MSIX_E610_CAPS	0xB2
 #define IXGBE_PCIE_MSIX_82599_CAPS  0x72
 #define IXGBE_MAX_MSIX_VECTORS_82599	0x40
 #define IXGBE_PCIE_MSIX_82598_CAPS  0x62
@@ -2168,6 +2180,7 @@ enum {
 #define IXGBE_PCI_DEVICE_STATUS   0xAA
 #define IXGBE_PCI_DEVICE_STATUS_TRANSACTION_PENDING   0x0020
 #define IXGBE_PCI_LINK_STATUS     0xB2
+#define IXGBE_PCI_LINK_STATUS_E610	0x82
 #define IXGBE_PCI_DEVICE_CONTROL2 0xC8
 #define IXGBE_PCI_LINK_WIDTH      0x3F0
 #define IXGBE_PCI_LINK_WIDTH_1    0x10
@@ -2288,6 +2301,7 @@ enum {
 #define IXGBE_RXMTRL_V2_MGMT_MSG		0x0D00
 
 #define IXGBE_FCTRL_SBP 0x00000002 /* Store Bad Packet */
+#define IXGBE_FCTRL_TPE 0x00000080 /* Tag Promiscuous Ena*/
 #define IXGBE_FCTRL_MPE 0x00000100 /* Multicast Promiscuous Ena*/
 #define IXGBE_FCTRL_UPE 0x00000200 /* Unicast Promiscuous Ena */
 #define IXGBE_FCTRL_BAM 0x00000400 /* Broadcast Accept Mode */
@@ -2351,6 +2365,7 @@ enum {
 /* Multiple Transmit Queue Command Register */
 #define IXGBE_MTQC_RT_ENA       0x1 /* DCB Enable */
 #define IXGBE_MTQC_VT_ENA       0x2 /* VMDQ2 Enable */
+#define IXGBE_MTQC_NUM_TC_OR_Q  0xC /* Number of TCs or TxQs per pool */
 #define IXGBE_MTQC_64Q_1PB      0x0 /* 64 queues 1 pack buffer */
 #define IXGBE_MTQC_32VF         0x8 /* 4 TX Queues per pool w/32VF's */
 #define IXGBE_MTQC_64VF         0x4 /* 2 TX Queues per pool w/64VF's */
@@ -2970,6 +2985,29 @@ typedef u32 ixgbe_link_speed;
 					IXGBE_LINK_SPEED_1GB_FULL | \
 					IXGBE_LINK_SPEED_10GB_FULL)
 
+/* Physical layer type */
+typedef u64 ixgbe_physical_layer;
+#define IXGBE_PHYSICAL_LAYER_UNKNOWN		0
+#define IXGBE_PHYSICAL_LAYER_10GBASE_T		0x00001
+#define IXGBE_PHYSICAL_LAYER_1000BASE_T		0x00002
+#define IXGBE_PHYSICAL_LAYER_100BASE_TX		0x00004
+#define IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU	0x00008
+#define IXGBE_PHYSICAL_LAYER_10GBASE_LR		0x00010
+#define IXGBE_PHYSICAL_LAYER_10GBASE_LRM	0x00020
+#define IXGBE_PHYSICAL_LAYER_10GBASE_SR		0x00040
+#define IXGBE_PHYSICAL_LAYER_10GBASE_KX4	0x00080
+#define IXGBE_PHYSICAL_LAYER_10GBASE_CX4	0x00100
+#define IXGBE_PHYSICAL_LAYER_1000BASE_KX	0x00200
+#define IXGBE_PHYSICAL_LAYER_1000BASE_BX	0x00400
+#define IXGBE_PHYSICAL_LAYER_10GBASE_KR		0x00800
+#define IXGBE_PHYSICAL_LAYER_10GBASE_XAUI	0x01000
+#define IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA	0x02000
+#define IXGBE_PHYSICAL_LAYER_1000BASE_SX	0x04000
+#define IXGBE_PHYSICAL_LAYER_10BASE_T		0x08000
+#define IXGBE_PHYSICAL_LAYER_2500BASE_KX	0x10000
+#define IXGBE_PHYSICAL_LAYER_2500BASE_T		0x20000
+#define IXGBE_PHYSICAL_LAYER_5000BASE_T		0x40000
+
 /* Flow Control Data Sheet defined values
  * Calculation and defines taken from 802.1bb Annex O
  */
@@ -3145,6 +3183,8 @@ enum ixgbe_mac_type {
 	ixgbe_mac_X550,
 	ixgbe_mac_X550EM_x,
 	ixgbe_mac_x550em_a,
+	ixgbe_mac_e610,
+	ixgbe_mac_e610_vf,
 	ixgbe_num_macs
 };
 
@@ -3224,7 +3264,9 @@ enum ixgbe_media_type {
 	ixgbe_media_type_copper,
 	ixgbe_media_type_backplane,
 	ixgbe_media_type_cx4,
-	ixgbe_media_type_virtual
+	ixgbe_media_type_virtual,
+	ixgbe_media_type_da,
+	ixgbe_media_type_aui,
 };
 
 /* Flow Control Settings */
@@ -3233,7 +3275,8 @@ enum ixgbe_fc_mode {
 	ixgbe_fc_rx_pause,
 	ixgbe_fc_tx_pause,
 	ixgbe_fc_full,
-	ixgbe_fc_default
+	ixgbe_fc_default,
+	ixgbe_fc_pfc,
 };
 
 /* Smart Speed Settings */
@@ -3533,6 +3576,9 @@ struct ixgbe_link_operations {
 struct ixgbe_link_info {
 	struct ixgbe_link_operations ops;
 	u8 addr;
+	struct ixgbe_link_status link_info;
+	struct ixgbe_link_status link_info_old;
+	u8 get_link_info;
 };
 
 struct ixgbe_eeprom_info {
@@ -3575,6 +3621,7 @@ struct ixgbe_mac_info {
 	u8				san_mac_rar_index;
 	struct ixgbe_thermal_sensor_data  thermal_sensor_data;
 	bool				set_lben;
+	u32				max_link_up_time;
 	u8				led_link_act;
 };
 
@@ -3599,6 +3646,10 @@ struct ixgbe_phy_info {
 	bool                            reset_if_overtemp;
 	bool                            qsfp_shared_i2c_bus;
 	u32				nw_mng_if_sel;
+	u64				phy_type_low;
+	u64				phy_type_high;
+	u16				curr_user_speed_req;
+	struct ixgbe_aci_cmd_set_phy_cfg_data curr_user_phy_cfg;
 };
 
 #include "ixgbe_mbx.h"
@@ -3654,6 +3705,19 @@ struct ixgbe_hw {
 	bool				allow_unsupported_sfp;
 	bool				wol_enabled;
 	bool				need_crosstalk_fix;
+	u8				api_branch;
+	u8				api_maj_ver;
+	u8				api_min_ver;
+	u8				api_patch;
+	u8				fw_branch;
+	u8				fw_maj_ver;
+	u8				fw_min_ver;
+	u8				fw_patch;
+	u32				fw_build;
+	struct ixgbe_aci_info		aci;
+	struct ixgbe_flash_info		flash;
+	struct ixgbe_hw_dev_caps	dev_caps;
+	struct ixgbe_hw_func_caps	func_caps;
 };
 
 struct ixgbe_info {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
new file mode 100644
index 0000000..6c6d990
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
@@ -0,0 +1,1066 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Intel Corporation. */
+
+#ifndef _IXGBE_TYPE_E610_H_
+#define _IXGBE_TYPE_E610_H_
+
+#define BYTES_PER_DWORD	4
+
+/* General E610 defines */
+#define IXGBE_MAX_VSI			768
+
+/* Checksum and Shadow RAM pointers */
+#define E610_SR_SW_CHECKSUM_WORD		0x3F
+
+/* Firmware Status Register (GL_FWSTS) */
+#define GL_FWSTS		0x00083048 /* Reset Source: POR */
+#define GL_FWSTS_EP_PF0		BIT(24)
+#define GL_FWSTS_EP_PF1		BIT(25)
+
+/* Flash Access Register */
+#define IXGBE_GLNVM_FLA			0x000B6108 /* Reset Source: POR */
+#define IXGBE_GLNVM_FLA_LOCKED_S	6
+#define IXGBE_GLNVM_FLA_LOCKED_M	BIT(6)
+
+/* Admin Command Interface (ACI) registers */
+#define IXGBE_PF_HIDA(_i)			(0x00085000 + ((_i) * 4))
+#define IXGBE_PF_HIDA_2(_i)			(0x00085020 + ((_i) * 4))
+#define IXGBE_PF_HIBA(_i)			(0x00084000 + ((_i) * 4))
+#define IXGBE_PF_HICR				0x00082048
+
+#define IXGBE_PF_HICR_EN			BIT(0)
+#define IXGBE_PF_HICR_C				BIT(1)
+#define IXGBE_PF_HICR_SV			BIT(2)
+#define IXGBE_PF_HICR_EV			BIT(3)
+
+#define IXGBE_ACI_DESC_SIZE		32
+#define IXGBE_ACI_DESC_SIZE_IN_DWORDS	(IXGBE_ACI_DESC_SIZE / BYTES_PER_DWORD)
+
+#define IXGBE_ACI_MAX_BUFFER_SIZE		4096    /* Size in bytes */
+#define IXGBE_ACI_SEND_DELAY_TIME_MS		10
+#define IXGBE_ACI_SEND_MAX_EXECUTE		3
+#define IXGBE_ACI_SEND_TIMEOUT_MS		\
+		(IXGBE_ACI_SEND_MAX_EXECUTE * IXGBE_ACI_SEND_DELAY_TIME_MS)
+/* [ms] timeout of waiting for sync response */
+#define IXGBE_ACI_SYNC_RESPONSE_TIMEOUT		100000
+/* [ms] timeout of waiting for async response */
+#define IXGBE_ACI_ASYNC_RESPONSE_TIMEOUT	150000
+/* [ms] timeout of waiting for resource release */
+#define IXGBE_ACI_RELEASE_RES_TIMEOUT		10000
+
+/* FW defined boundary for a large buffer, 4k >= Large buffer > 512 bytes */
+#define IXGBE_ACI_LG_BUF		512
+
+/* Flags sub-structure
+ * |0  |1  |2  |3  |4  |5  |6  |7  |8  |9  |10 |11 |12 |13 |14 |15 |
+ * |DD |CMP|ERR|VFE| * *  RESERVED * * |LB |RD |VFC|BUF|SI |EI |FE |
+ */
+
+#define IXGBE_ACI_FLAG_DD	BIT(0) /* 0x1 */
+#define IXGBE_ACI_FLAG_CMP	BIT(1) /* 0x2 */
+#define IXGBE_ACI_FLAG_ERR	BIT(2) /* 0x4 */
+#define IXGBE_ACI_FLAG_VFE	BIT(3) /* 0x8 */
+#define IXGBE_ACI_FLAG_LB	BIT(9) /* 0x200 */
+#define IXGBE_ACI_FLAG_RD	BIT(10) /* 0x400 */
+#define IXGBE_ACI_FLAG_VFC	BIT(11) /* 0x800 */
+#define IXGBE_ACI_FLAG_BUF	BIT(12) /* 0x1000 */
+#define IXGBE_ACI_FLAG_SI	BIT(13) /* 0x2000 */
+#define IXGBE_ACI_FLAG_EI	BIT(14) /* 0x4000 */
+#define IXGBE_ACI_FLAG_FE	BIT(15) /* 0x8000 */
+
+/* Admin Command Interface (ACI) error codes */
+enum ixgbe_aci_err {
+	IXGBE_ACI_RC_OK		= 0,  /* Success */
+	IXGBE_ACI_RC_EPERM	= 1,  /* Operation not permitted */
+	IXGBE_ACI_RC_ENOENT	= 2,  /* No such element */
+	IXGBE_ACI_RC_ESRCH	= 3,  /* Bad opcode */
+	IXGBE_ACI_RC_EINTR	= 4,  /* Operation interrupted */
+	IXGBE_ACI_RC_EIO	= 5,  /* I/O error */
+	IXGBE_ACI_RC_ENXIO	= 6,  /* No such resource */
+	IXGBE_ACI_RC_E2BIG	= 7,  /* Arg too long */
+	IXGBE_ACI_RC_EAGAIN	= 8,  /* Try again */
+	IXGBE_ACI_RC_ENOMEM	= 9,  /* Out of memory */
+	IXGBE_ACI_RC_EACCES	= 10, /* Permission denied */
+	IXGBE_ACI_RC_EFAULT	= 11, /* Bad address */
+	IXGBE_ACI_RC_EBUSY	= 12, /* Device or resource busy */
+	IXGBE_ACI_RC_EEXIST	= 13, /* Object already exists */
+	IXGBE_ACI_RC_EINVAL	= 14, /* Invalid argument */
+	IXGBE_ACI_RC_ENOTTY	= 15, /* Not a typewriter */
+	IXGBE_ACI_RC_ENOSPC	= 16, /* No space left or alloc failure */
+	IXGBE_ACI_RC_ENOSYS	= 17, /* Function not implemented */
+	IXGBE_ACI_RC_ERANGE	= 18, /* Parameter out of range */
+	IXGBE_ACI_RC_EFLUSHED	= 19, /* Cmd flushed due to prev cmd error */
+	IXGBE_ACI_RC_BAD_ADDR	= 20, /* Descriptor contains a bad pointer */
+	IXGBE_ACI_RC_EMODE	= 21, /* Op not allowed in current dev mode */
+	IXGBE_ACI_RC_EFBIG	= 22, /* File too big */
+	IXGBE_ACI_RC_ESBCOMP	= 23, /* SB-IOSF completion unsuccessful */
+	IXGBE_ACI_RC_ENOSEC	= 24, /* Missing security manifest */
+	IXGBE_ACI_RC_EBADSIG	= 25, /* Bad RSA signature */
+	IXGBE_ACI_RC_ESVN	= 26, /* SVN number prohibits this package */
+	IXGBE_ACI_RC_EBADMAN	= 27, /* Manifest hash mismatch */
+	IXGBE_ACI_RC_EBADBUF	= 28, /* Buffer hash mismatches manifest */
+	IXGBE_ACI_RC_EACCES_BMCU	= 29, /* BMC Update in progress */
+};
+
+/* Admin Command Interface (ACI) opcodes */
+enum ixgbe_aci_opc {
+	ixgbe_aci_opc_get_ver				= 0x0001,
+	ixgbe_aci_opc_driver_ver			= 0x0002,
+	ixgbe_aci_opc_get_exp_err			= 0x0005,
+
+	/* resource ownership */
+	ixgbe_aci_opc_req_res				= 0x0008,
+	ixgbe_aci_opc_release_res			= 0x0009,
+
+	/* device/function capabilities */
+	ixgbe_aci_opc_list_func_caps			= 0x000A,
+	ixgbe_aci_opc_list_dev_caps			= 0x000B,
+
+	/* safe disable of RXEN */
+	ixgbe_aci_opc_disable_rxen			= 0x000C,
+
+	/* FW events */
+	ixgbe_aci_opc_get_fw_event			= 0x0014,
+
+	/* PHY commands */
+	ixgbe_aci_opc_get_phy_caps			= 0x0600,
+	ixgbe_aci_opc_set_phy_cfg			= 0x0601,
+	ixgbe_aci_opc_restart_an			= 0x0605,
+	ixgbe_aci_opc_get_link_status			= 0x0607,
+	ixgbe_aci_opc_set_event_mask			= 0x0613,
+	ixgbe_aci_opc_get_link_topo			= 0x06E0,
+	ixgbe_aci_opc_get_link_topo_pin			= 0x06E1,
+	ixgbe_aci_opc_read_i2c				= 0x06E2,
+	ixgbe_aci_opc_write_i2c				= 0x06E3,
+	ixgbe_aci_opc_read_mdio				= 0x06E4,
+	ixgbe_aci_opc_write_mdio			= 0x06E5,
+	ixgbe_aci_opc_set_gpio_by_func			= 0x06E6,
+	ixgbe_aci_opc_get_gpio_by_func			= 0x06E7,
+	ixgbe_aci_opc_set_gpio				= 0x06EC,
+	ixgbe_aci_opc_get_gpio				= 0x06ED,
+	ixgbe_aci_opc_sff_eeprom			= 0x06EE,
+	ixgbe_aci_opc_prog_topo_dev_nvm			= 0x06F2,
+	ixgbe_aci_opc_read_topo_dev_nvm			= 0x06F3,
+
+	/* NVM commands */
+	ixgbe_aci_opc_nvm_read				= 0x0701,
+	ixgbe_aci_opc_nvm_erase				= 0x0702,
+	ixgbe_aci_opc_nvm_write				= 0x0703,
+	ixgbe_aci_opc_nvm_cfg_read			= 0x0704,
+	ixgbe_aci_opc_nvm_cfg_write			= 0x0705,
+	ixgbe_aci_opc_nvm_checksum			= 0x0706,
+	ixgbe_aci_opc_nvm_write_activate		= 0x0707,
+	ixgbe_aci_opc_nvm_sr_dump			= 0x0707,
+	ixgbe_aci_opc_nvm_save_factory_settings		= 0x0708,
+	ixgbe_aci_opc_nvm_update_empr			= 0x0709,
+	ixgbe_aci_opc_nvm_pkg_data			= 0x070A,
+	ixgbe_aci_opc_nvm_pass_component_tbl		= 0x070B,
+
+	/* Alternate Structure Commands */
+	ixgbe_aci_opc_write_alt_direct			= 0x0900,
+	ixgbe_aci_opc_write_alt_indirect		= 0x0901,
+	ixgbe_aci_opc_read_alt_direct			= 0x0902,
+	ixgbe_aci_opc_read_alt_indirect			= 0x0903,
+	ixgbe_aci_opc_done_alt_write			= 0x0904,
+	ixgbe_aci_opc_clear_port_alt_write		= 0x0906,
+
+	/* debug commands */
+	ixgbe_aci_opc_debug_dump_internals		= 0xFF08,
+
+	/* SystemDiagnostic commands */
+	ixgbe_aci_opc_set_health_status_config		= 0xFF20,
+	ixgbe_aci_opc_get_supported_health_status_codes	= 0xFF21,
+	ixgbe_aci_opc_get_health_status			= 0xFF22,
+	ixgbe_aci_opc_clear_health_status		= 0xFF23,
+};
+
+/* Get version (direct 0x0001) */
+struct ixgbe_aci_cmd_get_ver {
+	u32 rom_ver;
+	u32 fw_build;
+	u8 fw_branch;
+	u8 fw_major;
+	u8 fw_minor;
+	u8 fw_patch;
+	u8 api_branch;
+	u8 api_major;
+	u8 api_minor;
+	u8 api_patch;
+};
+
+#define IXGBE_DRV_VER_STR_LEN_E610	32
+
+/* Send driver version (indirect 0x0002) */
+struct ixgbe_aci_cmd_driver_ver {
+	u8 major_ver;
+	u8 minor_ver;
+	u8 build_ver;
+	u8 subbuild_ver;
+	u8 reserved[4];
+	u32 addr_high;
+	u32 addr_low;
+};
+
+/* Get Expanded Error Code (0x0005, direct) */
+struct ixgbe_aci_cmd_get_exp_err {
+	u32 reason;
+#define IXGBE_ACI_EXPANDED_ERROR_NOT_PROVIDED	0xFFFFFFFF
+	u32 identifier;
+	u8 rsvd[8];
+};
+
+/* FW update timeout definitions are in milliseconds */
+#define IXGBE_NVM_TIMEOUT		180000
+
+enum ixgbe_aci_res_access_type {
+	IXGBE_RES_READ = 1,
+	IXGBE_RES_WRITE
+};
+
+enum ixgbe_aci_res_ids {
+	IXGBE_NVM_RES_ID = 1,
+	IXGBE_SPD_RES_ID,
+	IXGBE_CHANGE_LOCK_RES_ID,
+	IXGBE_GLOBAL_CFG_LOCK_RES_ID
+};
+
+/* Request resource ownership (direct 0x0008)
+ * Release resource ownership (direct 0x0009)
+ */
+struct ixgbe_aci_cmd_req_res {
+	u16 res_id;
+	u16 access_type;
+
+	/* Upon successful completion, FW writes this value and driver is
+	 * expected to release resource before timeout. This value is provided
+	 * in milliseconds.
+	 */
+	u32 timeout;
+#define IXGBE_ACI_RES_NVM_READ_DFLT_TIMEOUT_MS	3000
+#define IXGBE_ACI_RES_NVM_WRITE_DFLT_TIMEOUT_MS	180000
+#define IXGBE_ACI_RES_CHNG_LOCK_DFLT_TIMEOUT_MS	1000
+#define IXGBE_ACI_RES_GLBL_LOCK_DFLT_TIMEOUT_MS	3000
+	/* For SDP: pin ID of the SDP */
+	u32 res_number;
+	u16 status;
+#define IXGBE_ACI_RES_GLBL_SUCCESS		0
+#define IXGBE_ACI_RES_GLBL_IN_PROG		1
+#define IXGBE_ACI_RES_GLBL_DONE			2
+	u8 reserved[2];
+};
+
+/* Get function capabilities (indirect 0x000A)
+ * Get device capabilities (indirect 0x000B)
+ */
+struct ixgbe_aci_cmd_list_caps {
+	u8 cmd_flags;
+	u8 pf_index;
+	u8 reserved[2];
+	u32 count;
+	u32 addr_high;
+	u32 addr_low;
+};
+
+/* Device/Function buffer entry, repeated per reported capability */
+struct ixgbe_aci_cmd_list_caps_elem {
+	u16 cap;
+#define IXGBE_ACI_CAPS_VALID_FUNCTIONS			0x0005
+#define IXGBE_ACI_MAX_VALID_FUNCTIONS			0x8
+#define IXGBE_ACI_CAPS_SRIOV				0x0012
+#define IXGBE_ACI_CAPS_VF				0x0013
+#define IXGBE_ACI_CAPS_VMDQ				0x0014
+#define IXGBE_ACI_CAPS_VSI				0x0017
+#define IXGBE_ACI_CAPS_DCB				0x0018
+#define IXGBE_ACI_CAPS_RSS				0x0040
+#define IXGBE_ACI_CAPS_RXQS				0x0041
+#define IXGBE_ACI_CAPS_TXQS				0x0042
+#define IXGBE_ACI_CAPS_MSIX				0x0043
+#define IXGBE_ACI_CAPS_FD				0x0045
+#define IXGBE_ACI_CAPS_1588				0x0046
+#define IXGBE_ACI_CAPS_MAX_MTU				0x0047
+#define IXGBE_ACI_CAPS_NVM_VER				0x0048
+#define IXGBE_ACI_CAPS_PENDING_NVM_VER			0x0049
+#define IXGBE_ACI_CAPS_OROM_VER				0x004A
+#define IXGBE_ACI_CAPS_PENDING_OROM_VER			0x004B
+#define IXGBE_ACI_CAPS_PENDING_NET_VER			0x004D
+#define IXGBE_ACI_CAPS_INLINE_IPSEC			0x0070
+#define IXGBE_ACI_CAPS_NUM_ENABLED_PORTS		0x0072
+#define IXGBE_ACI_CAPS_PCIE_RESET_AVOIDANCE		0x0076
+#define IXGBE_ACI_CAPS_POST_UPDATE_RESET_RESTRICT	0x0077
+#define IXGBE_ACI_CAPS_NVM_MGMT				0x0080
+#define IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG0		0x0081
+#define IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG1		0x0082
+#define IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG2		0x0083
+#define IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG3		0x0084
+	u8 major_ver;
+	u8 minor_ver;
+	/* Number of resources described by this capability */
+	u32 number;
+	/* Only meaningful for some types of resources */
+	u32 logical_id;
+	/* Only meaningful for some types of resources */
+	u32 phys_id;
+	u64 rsvd1;
+	u64 rsvd2;
+};
+
+/* Disable RXEN (direct 0x000C) */
+struct ixgbe_aci_cmd_disable_rxen {
+	u8 lport_num;
+	u8 reserved[15];
+};
+
+/* Get PHY capabilities (indirect 0x0600) */
+struct ixgbe_aci_cmd_get_phy_caps {
+	u8 lport_num;
+	u8 reserved;
+	u16 param0;
+	/* 18.0 - Report qualified modules */
+#define IXGBE_ACI_GET_PHY_RQM		BIT(0)
+	/* 18.1 - 18.3 : Report mode
+	 * 000b - Report topology capabilities, without media
+	 * 001b - Report topology capabilities, with media
+	 * 010b - Report Active configuration
+	 * 011b - Report PHY Type and FEC mode capabilities
+	 * 100b - Report Default capabilities
+	 */
+#define IXGBE_ACI_REPORT_MODE_M			GENMASK(3, 1)
+#define IXGBE_ACI_REPORT_TOPO_CAP_NO_MEDIA	0
+#define IXGBE_ACI_REPORT_TOPO_CAP_MEDIA		BIT(1)
+#define IXGBE_ACI_REPORT_ACTIVE_CFG		BIT(2)
+#define IXGBE_ACI_REPORT_DFLT_CFG		BIT(3)
+	u32 reserved1;
+	u32 addr_high;
+	u32 addr_low;
+};
+
+/* This is #define of PHY type (Extended):
+ * The first set of defines is for phy_type_low.
+ */
+#define IXGBE_PHY_TYPE_LOW_100BASE_TX		BIT_ULL(0)
+#define IXGBE_PHY_TYPE_LOW_100M_SGMII		BIT_ULL(1)
+#define IXGBE_PHY_TYPE_LOW_1000BASE_T		BIT_ULL(2)
+#define IXGBE_PHY_TYPE_LOW_1000BASE_SX		BIT_ULL(3)
+#define IXGBE_PHY_TYPE_LOW_1000BASE_LX		BIT_ULL(4)
+#define IXGBE_PHY_TYPE_LOW_1000BASE_KX		BIT_ULL(5)
+#define IXGBE_PHY_TYPE_LOW_1G_SGMII		BIT_ULL(6)
+#define IXGBE_PHY_TYPE_LOW_2500BASE_T		BIT_ULL(7)
+#define IXGBE_PHY_TYPE_LOW_2500BASE_X		BIT_ULL(8)
+#define IXGBE_PHY_TYPE_LOW_2500BASE_KX		BIT_ULL(9)
+#define IXGBE_PHY_TYPE_LOW_5GBASE_T		BIT_ULL(10)
+#define IXGBE_PHY_TYPE_LOW_5GBASE_KR		BIT_ULL(11)
+#define IXGBE_PHY_TYPE_LOW_10GBASE_T		BIT_ULL(12)
+#define IXGBE_PHY_TYPE_LOW_10G_SFI_DA		BIT_ULL(13)
+#define IXGBE_PHY_TYPE_LOW_10GBASE_SR		BIT_ULL(14)
+#define IXGBE_PHY_TYPE_LOW_10GBASE_LR		BIT_ULL(15)
+#define IXGBE_PHY_TYPE_LOW_10GBASE_KR_CR1	BIT_ULL(16)
+#define IXGBE_PHY_TYPE_LOW_10G_SFI_AOC_ACC	BIT_ULL(17)
+#define IXGBE_PHY_TYPE_LOW_10G_SFI_C2C		BIT_ULL(18)
+#define IXGBE_PHY_TYPE_LOW_25GBASE_T		BIT_ULL(19)
+#define IXGBE_PHY_TYPE_LOW_25GBASE_CR		BIT_ULL(20)
+#define IXGBE_PHY_TYPE_LOW_25GBASE_CR_S		BIT_ULL(21)
+#define IXGBE_PHY_TYPE_LOW_25GBASE_CR1		BIT_ULL(22)
+#define IXGBE_PHY_TYPE_LOW_25GBASE_SR		BIT_ULL(23)
+#define IXGBE_PHY_TYPE_LOW_25GBASE_LR		BIT_ULL(24)
+#define IXGBE_PHY_TYPE_LOW_25GBASE_KR		BIT_ULL(25)
+#define IXGBE_PHY_TYPE_LOW_25GBASE_KR_S		BIT_ULL(26)
+#define IXGBE_PHY_TYPE_LOW_25GBASE_KR1		BIT_ULL(27)
+#define IXGBE_PHY_TYPE_LOW_25G_AUI_AOC_ACC	BIT_ULL(28)
+#define IXGBE_PHY_TYPE_LOW_25G_AUI_C2C		BIT_ULL(29)
+#define IXGBE_PHY_TYPE_LOW_MAX_INDEX		29
+/* The second set of defines is for phy_type_high. */
+#define IXGBE_PHY_TYPE_HIGH_10BASE_T		BIT_ULL(1)
+#define IXGBE_PHY_TYPE_HIGH_10M_SGMII		BIT_ULL(2)
+#define IXGBE_PHY_TYPE_HIGH_2500M_SGMII		BIT_ULL(56)
+#define IXGBE_PHY_TYPE_HIGH_100M_USXGMII	BIT_ULL(57)
+#define IXGBE_PHY_TYPE_HIGH_1G_USXGMII		BIT_ULL(58)
+#define IXGBE_PHY_TYPE_HIGH_2500M_USXGMII	BIT_ULL(59)
+#define IXGBE_PHY_TYPE_HIGH_5G_USXGMII		BIT_ULL(60)
+#define IXGBE_PHY_TYPE_HIGH_10G_USXGMII		BIT_ULL(61)
+#define IXGBE_PHY_TYPE_HIGH_MAX_INDEX		61
+
+struct ixgbe_aci_cmd_get_phy_caps_data {
+	u64 phy_type_low; /* Use values from IXGBE_PHY_TYPE_LOW_* */
+	u64 phy_type_high; /* Use values from IXGBE_PHY_TYPE_HIGH_* */
+	u8 caps;
+#define IXGBE_ACI_PHY_EN_TX_LINK_PAUSE			BIT(0)
+#define IXGBE_ACI_PHY_EN_RX_LINK_PAUSE			BIT(1)
+#define IXGBE_ACI_PHY_LOW_POWER_MODE			BIT(2)
+#define IXGBE_ACI_PHY_EN_LINK				BIT(3)
+#define IXGBE_ACI_PHY_AN_MODE				BIT(4)
+#define IXGBE_ACI_PHY_EN_MOD_QUAL			BIT(5)
+#define IXGBE_ACI_PHY_EN_LESM				BIT(6)
+#define IXGBE_ACI_PHY_EN_AUTO_FEC			BIT(7)
+#define IXGBE_ACI_PHY_CAPS_MASK				GENMASK(7, 0)
+	u8 low_power_ctrl_an;
+#define IXGBE_ACI_PHY_EN_D3COLD_LOW_POWER_AUTONEG	BIT(0)
+#define IXGBE_ACI_PHY_AN_EN_CLAUSE28			BIT(1)
+#define IXGBE_ACI_PHY_AN_EN_CLAUSE73			BIT(2)
+#define IXGBE_ACI_PHY_AN_EN_CLAUSE37			BIT(3)
+	u16 eee_cap;
+#define IXGBE_ACI_PHY_EEE_EN_100BASE_TX			BIT(0)
+#define IXGBE_ACI_PHY_EEE_EN_1000BASE_T			BIT(1)
+#define IXGBE_ACI_PHY_EEE_EN_10GBASE_T			BIT(2)
+#define IXGBE_ACI_PHY_EEE_EN_1000BASE_KX		BIT(3)
+#define IXGBE_ACI_PHY_EEE_EN_10GBASE_KR			BIT(4)
+#define IXGBE_ACI_PHY_EEE_EN_25GBASE_KR			BIT(5)
+#define IXGBE_ACI_PHY_EEE_EN_10BASE_T			BIT(11)
+	u16 eeer_value;
+	u8 phy_id_oui[4]; /* PHY/Module ID connected on the port */
+	u8 phy_fw_ver[8];
+	u8 link_fec_options;
+#define IXGBE_ACI_PHY_FEC_10G_KR_40G_KR4_EN		BIT(0)
+#define IXGBE_ACI_PHY_FEC_10G_KR_40G_KR4_REQ		BIT(1)
+#define IXGBE_ACI_PHY_FEC_25G_RS_528_REQ		BIT(2)
+#define IXGBE_ACI_PHY_FEC_25G_KR_REQ			BIT(3)
+#define IXGBE_ACI_PHY_FEC_25G_RS_544_REQ		BIT(4)
+#define IXGBE_ACI_PHY_FEC_25G_RS_CLAUSE91_EN		BIT(6)
+#define IXGBE_ACI_PHY_FEC_25G_KR_CLAUSE74_EN		BIT(7)
+#define IXGBE_ACI_PHY_FEC_MASK				0xdf
+	u8 module_compliance_enforcement;
+#define IXGBE_ACI_MOD_ENFORCE_STRICT_MODE		BIT(0)
+	u8 extended_compliance_code;
+#define IXGBE_ACI_MODULE_TYPE_TOTAL_BYTE		3
+	u8 module_type[IXGBE_ACI_MODULE_TYPE_TOTAL_BYTE];
+#define IXGBE_ACI_MOD_TYPE_BYTE0_SFP_PLUS		0xA0
+#define IXGBE_ACI_MOD_TYPE_BYTE0_QSFP_PLUS		0x80
+#define IXGBE_ACI_MOD_TYPE_IDENT			1
+#define IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_PASSIVE	BIT(0)
+#define IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_ACTIVE	BIT(1)
+#define IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_SR		BIT(4)
+#define IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_LR		BIT(5)
+#define IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_LRM		BIT(6)
+#define IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_ER		BIT(7)
+#define IXGBE_ACI_MOD_TYPE_BYTE2_SFP_PLUS		0xA0
+#define IXGBE_ACI_MOD_TYPE_BYTE2_QSFP_PLUS		0x86
+	u8 qualified_module_count;
+	u8 rsvd2[7];	/* Bytes 47:41 reserved */
+#define IXGBE_ACI_QUAL_MOD_COUNT_MAX			16
+	struct {
+		u8 v_oui[3];
+		u8 rsvd3;
+		u8 v_part[16];
+		u32 v_rev;
+		u64 rsvd4;
+	} qual_modules[IXGBE_ACI_QUAL_MOD_COUNT_MAX];
+};
+
+/* Set PHY capabilities (direct 0x0601)
+ * NOTE: This command must be followed by setup link and restart auto-neg
+ */
+struct ixgbe_aci_cmd_set_phy_cfg {
+	u8 lport_num;
+	u8 reserved[7];
+	u32 addr_high;
+	u32 addr_low;
+};
+
+/* Set PHY config command data structure */
+struct ixgbe_aci_cmd_set_phy_cfg_data {
+	u64 phy_type_low; /* Use values from IXGBE_PHY_TYPE_LOW_* */
+	u64 phy_type_high; /* Use values from IXGBE_PHY_TYPE_HIGH_* */
+	u8 caps;
+#define IXGBE_ACI_PHY_ENA_VALID_MASK		0xef
+#define IXGBE_ACI_PHY_ENA_TX_PAUSE_ABILITY	BIT(0)
+#define IXGBE_ACI_PHY_ENA_RX_PAUSE_ABILITY	BIT(1)
+#define IXGBE_ACI_PHY_ENA_LOW_POWER		BIT(2)
+#define IXGBE_ACI_PHY_ENA_LINK			BIT(3)
+#define IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT	BIT(5)
+#define IXGBE_ACI_PHY_ENA_LESM			BIT(6)
+#define IXGBE_ACI_PHY_ENA_AUTO_FEC		BIT(7)
+	u8 low_power_ctrl_an;
+	u16 eee_cap; /* Value from ixgbe_aci_get_phy_caps */
+	u16 eeer_value; /* Use defines from ixgbe_aci_get_phy_caps */
+	u8 link_fec_opt; /* Use defines from ixgbe_aci_get_phy_caps */
+	u8 module_compliance_enforcement;
+};
+
+/* Restart AN command data structure (direct 0x0605)
+ * Also used for response, with only the lport_num field present.
+ */
+struct ixgbe_aci_cmd_restart_an {
+	u8 lport_num;
+	u8 reserved;
+	u8 cmd_flags;
+#define IXGBE_ACI_RESTART_AN_LINK_RESTART	BIT(1)
+#define IXGBE_ACI_RESTART_AN_LINK_ENABLE	BIT(2)
+	u8 reserved2[13];
+};
+
+/* Get link status (indirect 0x0607), also used for Link Status Event */
+struct ixgbe_aci_cmd_get_link_status {
+	u8 lport_num;
+	u8 reserved;
+	u16 cmd_flags;
+#define IXGBE_ACI_LSE_M				GENMASK(1, 0)
+#define IXGBE_ACI_LSE_NOP			0x0
+#define IXGBE_ACI_LSE_DIS			0x2
+#define IXGBE_ACI_LSE_ENA			0x3
+	/* only response uses this flag */
+#define IXGBE_ACI_LSE_IS_ENABLED		0x1
+	u32 reserved2;
+	u32 addr_high;
+	u32 addr_low;
+};
+
+/* Get link status response data structure, also used for Link Status Event */
+struct ixgbe_aci_cmd_get_link_status_data {
+	u8 topo_media_conflict;
+#define IXGBE_ACI_LINK_TOPO_CONFLICT		BIT(0)
+#define IXGBE_ACI_LINK_MEDIA_CONFLICT		BIT(1)
+#define IXGBE_ACI_LINK_TOPO_CORRUPT		BIT(2)
+#define IXGBE_ACI_LINK_TOPO_UNREACH_PRT		BIT(4)
+#define IXGBE_ACI_LINK_TOPO_UNDRUTIL_PRT	BIT(5)
+#define IXGBE_ACI_LINK_TOPO_UNDRUTIL_MEDIA	BIT(6)
+#define IXGBE_ACI_LINK_TOPO_UNSUPP_MEDIA	BIT(7)
+	u8 link_cfg_err;
+#define IXGBE_ACI_LINK_CFG_ERR				BIT(0)
+#define IXGBE_ACI_LINK_CFG_COMPLETED			BIT(1)
+#define IXGBE_ACI_LINK_ACT_PORT_OPT_INVAL		BIT(2)
+#define IXGBE_ACI_LINK_FEAT_ID_OR_CONFIG_ID_INVAL	BIT(3)
+#define IXGBE_ACI_LINK_TOPO_CRITICAL_SDP_ERR		BIT(4)
+#define IXGBE_ACI_LINK_MODULE_POWER_UNSUPPORTED		BIT(5)
+#define IXGBE_ACI_LINK_EXTERNAL_PHY_LOAD_FAILURE	BIT(6)
+#define IXGBE_ACI_LINK_INVAL_MAX_POWER_LIMIT		BIT(7)
+	u8 link_info;
+#define IXGBE_ACI_LINK_UP		BIT(0)	/* Link Status */
+#define IXGBE_ACI_LINK_FAULT		BIT(1)
+#define IXGBE_ACI_LINK_FAULT_TX		BIT(2)
+#define IXGBE_ACI_LINK_FAULT_RX		BIT(3)
+#define IXGBE_ACI_LINK_FAULT_REMOTE	BIT(4)
+#define IXGBE_ACI_LINK_UP_PORT		BIT(5)	/* External Port Link Status */
+#define IXGBE_ACI_MEDIA_AVAILABLE	BIT(6)
+#define IXGBE_ACI_SIGNAL_DETECT		BIT(7)
+	u8 an_info;
+#define IXGBE_ACI_AN_COMPLETED		BIT(0)
+#define IXGBE_ACI_LP_AN_ABILITY		BIT(1)
+#define IXGBE_ACI_PD_FAULT		BIT(2)	/* Parallel Detection Fault */
+#define IXGBE_ACI_FEC_EN		BIT(3)
+#define IXGBE_ACI_PHY_LOW_POWER		BIT(4)	/* Low Power State */
+#define IXGBE_ACI_LINK_PAUSE_TX		BIT(5)
+#define IXGBE_ACI_LINK_PAUSE_RX		BIT(6)
+#define IXGBE_ACI_QUALIFIED_MODULE	BIT(7)
+	u8 ext_info;
+#define IXGBE_ACI_LINK_PHY_TEMP_ALARM	BIT(0)
+#define IXGBE_ACI_LINK_EXCESSIVE_ERRORS	BIT(1)	/* Excessive Link Errors */
+	/* Port Tx Suspended */
+#define IXGBE_ACI_LINK_TX_ACTIVE	0
+#define IXGBE_ACI_LINK_TX_DRAINED	1
+#define IXGBE_ACI_LINK_TX_FLUSHED	3
+	u8 lb_status;
+#define IXGBE_ACI_LINK_LB_PHY_LCL	BIT(0)
+#define IXGBE_ACI_LINK_LB_PHY_RMT	BIT(1)
+#define IXGBE_ACI_LINK_LB_MAC_LCL	BIT(2)
+	u16 max_frame_size;
+	u8 cfg;
+#define IXGBE_ACI_LINK_25G_KR_FEC_EN		BIT(0)
+#define IXGBE_ACI_LINK_25G_RS_528_FEC_EN	BIT(1)
+#define IXGBE_ACI_LINK_25G_RS_544_FEC_EN	BIT(2)
+#define IXGBE_ACI_FEC_MASK			GENMASK(2, 0)
+	/* Pacing Config */
+#define IXGBE_ACI_CFG_PACING_M		GENMASK(6, 3)
+#define IXGBE_ACI_CFG_PACING_TYPE_M	BIT(7)
+#define IXGBE_ACI_CFG_PACING_TYPE_AVG	0
+#define IXGBE_ACI_CFG_PACING_TYPE_FIXED	IXGBE_ACI_CFG_PACING_TYPE_M
+	/* External Device Power Ability */
+	u8 power_desc;
+#define IXGBE_ACI_PWR_CLASS_M			GENMASK(5, 0)
+#define IXGBE_ACI_LINK_PWR_BASET_LOW_HIGH	0
+#define IXGBE_ACI_LINK_PWR_BASET_HIGH		1
+#define IXGBE_ACI_LINK_PWR_QSFP_CLASS_1		0
+#define IXGBE_ACI_LINK_PWR_QSFP_CLASS_2		1
+#define IXGBE_ACI_LINK_PWR_QSFP_CLASS_3		2
+#define IXGBE_ACI_LINK_PWR_QSFP_CLASS_4		3
+	u16 link_speed;
+#define IXGBE_ACI_LINK_SPEED_M			GENMASK(10, 0)
+#define IXGBE_ACI_LINK_SPEED_10MB		BIT(0)
+#define IXGBE_ACI_LINK_SPEED_100MB		BIT(1)
+#define IXGBE_ACI_LINK_SPEED_1000MB		BIT(2)
+#define IXGBE_ACI_LINK_SPEED_2500MB		BIT(3)
+#define IXGBE_ACI_LINK_SPEED_5GB		BIT(4)
+#define IXGBE_ACI_LINK_SPEED_10GB		BIT(5)
+#define IXGBE_ACI_LINK_SPEED_20GB		BIT(6)
+#define IXGBE_ACI_LINK_SPEED_25GB		BIT(7)
+#define IXGBE_ACI_LINK_SPEED_40GB		BIT(8)
+#define IXGBE_ACI_LINK_SPEED_50GB		BIT(9)
+#define IXGBE_ACI_LINK_SPEED_100GB		BIT(10)
+#define IXGBE_ACI_LINK_SPEED_200GB		BIT(11)
+#define IXGBE_ACI_LINK_SPEED_UNKNOWN		BIT(15)
+	u16 reserved3;
+	u8 ext_fec_status;
+#define IXGBE_ACI_LINK_RS_272_FEC_EN	BIT(0) /* RS 272 FEC enabled */
+	u8 reserved4;
+	u64 phy_type_low; /* Use values from ICE_PHY_TYPE_LOW_* */
+	u64 phy_type_high; /* Use values from ICE_PHY_TYPE_HIGH_* */
+	/* Get link status version 2 link partner data */
+	u64 lp_phy_type_low; /* Use values from ICE_PHY_TYPE_LOW_* */
+	u64 lp_phy_type_high; /* Use values from ICE_PHY_TYPE_HIGH_* */
+	u8 lp_fec_adv;
+#define IXGBE_ACI_LINK_LP_10G_KR_FEC_CAP	BIT(0)
+#define IXGBE_ACI_LINK_LP_25G_KR_FEC_CAP	BIT(1)
+#define IXGBE_ACI_LINK_LP_RS_528_FEC_CAP	BIT(2)
+#define IXGBE_ACI_LINK_LP_50G_KR_272_FEC_CAP	BIT(3)
+#define IXGBE_ACI_LINK_LP_100G_KR_272_FEC_CAP	BIT(4)
+#define IXGBE_ACI_LINK_LP_200G_KR_272_FEC_CAP	BIT(5)
+	u8 lp_fec_req;
+#define IXGBE_ACI_LINK_LP_10G_KR_FEC_REQ	BIT(0)
+#define IXGBE_ACI_LINK_LP_25G_KR_FEC_REQ	BIT(1)
+#define IXGBE_ACI_LINK_LP_RS_528_FEC_REQ	BIT(2)
+#define IXGBE_ACI_LINK_LP_KR_272_FEC_REQ	BIT(3)
+	u8 lp_flowcontrol;
+#define IXGBE_ACI_LINK_LP_PAUSE_ADV		BIT(0)
+#define IXGBE_ACI_LINK_LP_ASM_DIR_ADV		BIT(1)
+	u8 reserved5[5];
+} __packed;
+
+/* Set event mask command (direct 0x0613) */
+struct ixgbe_aci_cmd_set_event_mask {
+	u8	lport_num;
+	u8	reserved[7];
+	u16	event_mask;
+#define IXGBE_ACI_LINK_EVENT_UPDOWN		BIT(1)
+#define IXGBE_ACI_LINK_EVENT_MEDIA_NA		BIT(2)
+#define IXGBE_ACI_LINK_EVENT_LINK_FAULT		BIT(3)
+#define IXGBE_ACI_LINK_EVENT_PHY_TEMP_ALARM	BIT(4)
+#define IXGBE_ACI_LINK_EVENT_EXCESSIVE_ERRORS	BIT(5)
+#define IXGBE_ACI_LINK_EVENT_SIGNAL_DETECT	BIT(6)
+#define IXGBE_ACI_LINK_EVENT_AN_COMPLETED	BIT(7)
+#define IXGBE_ACI_LINK_EVENT_MODULE_QUAL_FAIL	BIT(8)
+#define IXGBE_ACI_LINK_EVENT_PORT_TX_SUSPENDED	BIT(9)
+#define IXGBE_ACI_LINK_EVENT_TOPO_CONFLICT	BIT(10)
+#define IXGBE_ACI_LINK_EVENT_MEDIA_CONFLICT	BIT(11)
+#define IXGBE_ACI_LINK_EVENT_PHY_FW_LOAD_FAIL	BIT(12)
+	u8	reserved1[6];
+};
+
+struct ixgbe_aci_cmd_link_topo_params {
+	u8 lport_num;
+	u8 lport_num_valid;
+#define IXGBE_ACI_LINK_TOPO_PORT_NUM_VALID	BIT(0)
+	u8 node_type_ctx;
+#define IXGBE_ACI_LINK_TOPO_NODE_TYPE_M		GENMASK(3, 0)
+#define IXGBE_ACI_LINK_TOPO_NODE_TYPE_PHY	0
+#define IXGBE_ACI_LINK_TOPO_NODE_TYPE_GPIO_CTRL	1
+#define IXGBE_ACI_LINK_TOPO_NODE_TYPE_MUX_CTRL	2
+#define IXGBE_ACI_LINK_TOPO_NODE_TYPE_LED_CTRL	3
+#define IXGBE_ACI_LINK_TOPO_NODE_TYPE_LED	4
+#define IXGBE_ACI_LINK_TOPO_NODE_TYPE_THERMAL	5
+#define IXGBE_ACI_LINK_TOPO_NODE_TYPE_CAGE	6
+#define IXGBE_ACI_LINK_TOPO_NODE_TYPE_MEZZ	7
+#define IXGBE_ACI_LINK_TOPO_NODE_TYPE_ID_EEPROM	8
+#define IXGBE_ACI_LINK_TOPO_NODE_TYPE_CLK_CTRL	9
+#define IXGBE_ACI_LINK_TOPO_NODE_TYPE_CLK_MUX	10
+#define IXGBE_ACI_LINK_TOPO_NODE_TYPE_GPS	11
+#define IXGBE_ACI_LINK_TOPO_NODE_CTX_S		4
+#define IXGBE_ACI_LINK_TOPO_NODE_CTX_GLOBAL			0
+#define IXGBE_ACI_LINK_TOPO_NODE_CTX_BOARD			1
+#define IXGBE_ACI_LINK_TOPO_NODE_CTX_PORT			2
+#define IXGBE_ACI_LINK_TOPO_NODE_CTX_NODE			3
+#define IXGBE_ACI_LINK_TOPO_NODE_CTX_NODE_HANDLE		4
+#define IXGBE_ACI_LINK_TOPO_NODE_CTX_DIRECT_BUS_ACCESS		5
+#define IXGBE_ACI_LINK_TOPO_NODE_CTX_NODE_HANDLE_BUS_ADDRESS	6
+	u8 index;
+};
+
+struct ixgbe_aci_cmd_link_topo_addr {
+	struct ixgbe_aci_cmd_link_topo_params topo_params;
+	u16 handle;
+/* Used to decode the handle field */
+#define IXGBE_ACI_LINK_TOPO_HANDLE_BRD_TYPE_M		BIT(9)
+#define IXGBE_ACI_LINK_TOPO_HANDLE_BRD_TYPE_LOM		BIT(9)
+#define IXGBE_ACI_LINK_TOPO_HANDLE_BRD_TYPE_MEZZ	0
+};
+
+/* Get Link Topology Handle (direct, 0x06E0) */
+struct ixgbe_aci_cmd_get_link_topo {
+	struct ixgbe_aci_cmd_link_topo_addr addr;
+	u8 node_part_num;
+#define IXGBE_ACI_GET_LINK_TOPO_NODE_NR_PCA9575		0x21
+#define IXGBE_ACI_GET_LINK_TOPO_NODE_NR_ZL30632_80032	0x24
+#define IXGBE_ACI_GET_LINK_TOPO_NODE_NR_SI5384		0x25
+#define IXGBE_ACI_GET_LINK_TOPO_NODE_NR_C827		0x31
+#define IXGBE_ACI_GET_LINK_TOPO_NODE_NR_GEN_CLK_MUX	0x47
+#define IXGBE_ACI_GET_LINK_TOPO_NODE_NR_GEN_GPS		0x48
+#define IXGBE_ACI_GET_LINK_TOPO_NODE_NR_E610_PTC	0x49
+	u8 rsvd[9];
+};
+
+/* Get Link Topology Pin (direct, 0x06E1) */
+struct ixgbe_aci_cmd_get_link_topo_pin {
+	struct ixgbe_aci_cmd_link_topo_addr addr;
+	u8 input_io_params;
+#define IXGBE_ACI_LINK_TOPO_IO_FUNC_GPIO	0
+#define IXGBE_ACI_LINK_TOPO_IO_FUNC_RESET_N	1
+#define IXGBE_ACI_LINK_TOPO_IO_FUNC_INT_N	2
+#define IXGBE_ACI_LINK_TOPO_IO_FUNC_PRESENT_N	3
+#define IXGBE_ACI_LINK_TOPO_IO_FUNC_TX_DIS	4
+#define IXGBE_ACI_LINK_TOPO_IO_FUNC_MODSEL_N	5
+#define IXGBE_ACI_LINK_TOPO_IO_FUNC_LPMODE	6
+#define IXGBE_ACI_LINK_TOPO_IO_FUNC_TX_FAULT	7
+#define IXGBE_ACI_LINK_TOPO_IO_FUNC_RX_LOSS	8
+#define IXGBE_ACI_LINK_TOPO_IO_FUNC_RS0		9
+#define IXGBE_ACI_LINK_TOPO_IO_FUNC_RS1		10
+#define IXGBE_ACI_LINK_TOPO_IO_FUNC_EEPROM_WP	11
+/* 12 repeats intentionally due to two different uses depending on context */
+#define IXGBE_ACI_LINK_TOPO_IO_FUNC_LED		12
+#define IXGBE_ACI_LINK_TOPO_IO_FUNC_RED_LED	12
+#define IXGBE_ACI_LINK_TOPO_IO_FUNC_GREEN_LED	13
+#define IXGBE_ACI_LINK_TOPO_IO_FUNC_BLUE_LED	14
+#define IXGBE_ACI_LINK_TOPO_INPUT_IO_TYPE_GPIO	3
+/* Use IXGBE_ACI_LINK_TOPO_NODE_TYPE_* for the type values */
+	u8 output_io_params;
+/* Use IXGBE_ACI_LINK_TOPO_NODE_TYPE_* for the type values */
+	u8 output_io_flags;
+#define IXGBE_ACI_LINK_TOPO_OUTPUT_POLARITY	BIT(5)
+#define IXGBE_ACI_LINK_TOPO_OUTPUT_VALUE	BIT(6)
+#define IXGBE_ACI_LINK_TOPO_OUTPUT_DRIVEN	BIT(7)
+	u8 rsvd[7];
+};
+
+/* Read/Write SFF EEPROM command (indirect 0x06EE) */
+struct ixgbe_aci_cmd_sff_eeprom {
+	u8 lport_num;
+	u8 lport_num_valid;
+#define IXGBE_ACI_SFF_PORT_NUM_VALID		BIT(0)
+	u16 i2c_bus_addr;
+#define IXGBE_ACI_SFF_I2CBUS_7BIT_M		GENMASK(6, 0)
+#define IXGBE_ACI_SFF_I2CBUS_10BIT_M		GENMASK(9, 0)
+#define IXGBE_ACI_SFF_I2CBUS_TYPE_M		BIT(10)
+#define IXGBE_ACI_SFF_I2CBUS_TYPE_7BIT		0
+#define IXGBE_ACI_SFF_I2CBUS_TYPE_10BIT		IXGBE_ACI_SFF_I2CBUS_TYPE_M
+#define IXGBE_ACI_SFF_NO_PAGE_BANK_UPDATE	0
+#define IXGBE_ACI_SFF_UPDATE_PAGE		1
+#define IXGBE_ACI_SFF_UPDATE_BANK		2
+#define IXGBE_ACI_SFF_UPDATE_PAGE_BANK		3
+#define IXGBE_ACI_SFF_IS_WRITE			BIT(15)
+	u16 i2c_offset;
+	u8 module_bank;
+	u8 module_page;
+	u32 addr_high;
+	u32 addr_low;
+};
+
+/* NVM Read command (indirect 0x0701)
+ * NVM Erase commands (direct 0x0702)
+ * NVM Write commands (indirect 0x0703)
+ * NVM Write Activate commands (direct 0x0707)
+ * NVM Shadow RAM Dump commands (direct 0x0707)
+ */
+struct ixgbe_aci_cmd_nvm {
+#define IXGBE_ACI_NVM_MAX_OFFSET	0xFFFFFF
+	u16 offset_low;
+	u8 offset_high; /* For Write Activate offset_high is used as flags2 */
+	u8 cmd_flags;
+#define IXGBE_ACI_NVM_LAST_CMD		BIT(0)
+#define IXGBE_ACI_NVM_PCIR_REQ		BIT(0) /* Used by NVM Write reply */
+#define IXGBE_ACI_NVM_PRESERVE_ALL	BIT(1)
+#define IXGBE_ACI_NVM_ACTIV_SEL_NVM	BIT(3) /* Write Activate/SR Dump only */
+#define IXGBE_ACI_NVM_ACTIV_SEL_OROM	BIT(4)
+#define IXGBE_ACI_NVM_ACTIV_SEL_NETLIST	BIT(5)
+#define IXGBE_ACI_NVM_SPECIAL_UPDATE	BIT(6)
+#define IXGBE_ACI_NVM_REVERT_LAST_ACTIV	BIT(6) /* Write Activate only */
+#define IXGBE_ACI_NVM_FLASH_ONLY	BIT(7)
+#define IXGBE_ACI_NVM_RESET_LVL_M	GENMASK(1, 0) /* Write reply only */
+#define IXGBE_ACI_NVM_POR_FLAG		0
+#define IXGBE_ACI_NVM_PERST_FLAG	1
+#define IXGBE_ACI_NVM_EMPR_FLAG		2
+#define IXGBE_ACI_NVM_EMPR_ENA		BIT(0) /* Write Activate reply only */
+	/* For Write Activate, several flags are sent as part of a separate
+	 * flags2 field using a separate byte. For simplicity of the software
+	 * interface, we pass the flags as a 16 bit value so these flags are
+	 * all offset by 8 bits
+	 */
+#define IXGBE_ACI_NVM_ACTIV_REQ_EMPR	BIT(8) /* NVM Write Activate only */
+	u16 module_typeid;
+	u16 length;
+#define IXGBE_ACI_NVM_ERASE_LEN	0xFFFF
+	u32 addr_high;
+	u32 addr_low;
+};
+
+/* NVM Module_Type ID, needed offset and read_len for
+ * struct ixgbe_aci_cmd_nvm.
+ */
+#define IXGBE_ACI_NVM_START_POINT		0
+
+/* NVM Checksum Command (direct, 0x0706) */
+struct ixgbe_aci_cmd_nvm_checksum {
+	u8 flags;
+#define IXGBE_ACI_NVM_CHECKSUM_VERIFY	BIT(0)
+#define IXGBE_ACI_NVM_CHECKSUM_RECALC	BIT(1)
+	u8 rsvd;
+	u16 checksum; /* Used only by response */
+#define IXGBE_ACI_NVM_CHECKSUM_CORRECT	0xBABA
+	u8 rsvd2[12];
+};
+
+/**
+ * struct ixgbe_aci_desc - Admin Command (AC) descriptor
+ * @flags: IXGBE_ACI_FLAG_* flags
+ * @opcode: Admin command opcode
+ * @datalen: length in bytes of indirect/external data buffer
+ * @retval: return value from firmware
+ * @cookie_high: opaque data high-half
+ * @cookie_low: opaque data low-half
+ * @params: command-specific parameters
+ *
+ * Descriptor format for commands the driver posts via the
+ * Admin Command Interface (ACI).
+ * The firmware writes back onto the command descriptor and returns
+ * the result of the command. Asynchronous events that are not an immediate
+ * result of the command are written to the Admin Command Interface (ACI) using
+ * the same descriptor format. Descriptors are in little-endian notation with
+ * 32-bit words.
+ */
+struct ixgbe_aci_desc {
+	u16 flags;
+	u16 opcode;
+	u16 datalen;
+	u16 retval;
+	u32 cookie_high;
+	u32 cookie_low;
+	union {
+		u8 raw[16];
+		struct ixgbe_aci_cmd_get_ver get_ver;
+		struct ixgbe_aci_cmd_driver_ver driver_ver;
+		struct ixgbe_aci_cmd_get_exp_err exp_err;
+		struct ixgbe_aci_cmd_req_res res_owner;
+		struct ixgbe_aci_cmd_list_caps get_cap;
+		struct ixgbe_aci_cmd_disable_rxen disable_rxen;
+		struct ixgbe_aci_cmd_get_phy_caps get_phy;
+		struct ixgbe_aci_cmd_set_phy_cfg set_phy;
+		struct ixgbe_aci_cmd_restart_an restart_an;
+		struct ixgbe_aci_cmd_get_link_status get_link_status;
+		struct ixgbe_aci_cmd_set_event_mask set_event_mask;
+		struct ixgbe_aci_cmd_get_link_topo get_link_topo;
+		struct ixgbe_aci_cmd_get_link_topo_pin get_link_topo_pin;
+		struct ixgbe_aci_cmd_sff_eeprom read_write_sff_param;
+		struct ixgbe_aci_cmd_nvm nvm;
+		struct ixgbe_aci_cmd_nvm_checksum nvm_checksum;
+	} params;
+};
+
+/* E610-specific adapter context structures */
+
+struct ixgbe_link_status {
+	/* Refer to ixgbe_aci_phy_type for bits definition */
+	u64 phy_type_low;
+	u64 phy_type_high;
+	u16 max_frame_size;
+	u16 link_speed;
+	u16 req_speeds;
+	u8 topo_media_conflict;
+	u8 link_cfg_err;
+	u8 lse_ena;	/* Link Status Event notification */
+	u8 link_info;
+	u8 an_info;
+	u8 ext_info;
+	u8 fec_info;
+	u8 pacing;
+	/* Refer to #define from module_type[IXGBE_ACI_MODULE_TYPE_TOTAL_BYTE]
+	 * of ixgbe_aci_get_phy_caps structure
+	 */
+	u8 module_type[IXGBE_ACI_MODULE_TYPE_TOTAL_BYTE];
+};
+
+/* Common HW capabilities for SW use */
+struct ixgbe_hw_caps {
+	/* Write CSR protection */
+	u64 wr_csr_prot;
+	u32 switching_mode;
+	/* switching mode supported - EVB switching (including cloud) */
+#define IXGBE_NVM_IMAGE_TYPE_EVB		0x0
+
+	/* Manageability mode & supported protocols over MCTP */
+	u32 mgmt_mode;
+#define IXGBE_MGMT_MODE_PASS_THRU_MODE_M	GENMASK(3, 0)
+#define IXGBE_MGMT_MODE_CTL_INTERFACE_M		GENMASK(7, 4)
+#define IXGBE_MGMT_MODE_REDIR_SB_INTERFACE_M	GENMASK(11, 8)
+
+	u32 mgmt_protocols_mctp;
+#define IXGBE_MGMT_MODE_PROTO_RSVD	BIT(0)
+#define IXGBE_MGMT_MODE_PROTO_PLDM	BIT(1)
+#define IXGBE_MGMT_MODE_PROTO_OEM	BIT(2)
+#define IXGBE_MGMT_MODE_PROTO_NC_SI	BIT(3)
+
+	u32 os2bmc;
+	u32 valid_functions;
+	/* DCB capabilities */
+	u32 active_tc_bitmap;
+	u32 maxtc;
+
+	/* RSS related capabilities */
+	u32 rss_table_size;		/* 512 for PFs and 64 for VFs */
+	u32 rss_table_entry_width;	/* RSS Entry width in bits */
+
+	/* Tx/Rx queues */
+	u32 num_rxq;			/* Number/Total Rx queues */
+	u32 rxq_first_id;		/* First queue ID for Rx queues */
+	u32 num_txq;			/* Number/Total Tx queues */
+	u32 txq_first_id;		/* First queue ID for Tx queues */
+
+	/* MSI-X vectors */
+	u32 num_msix_vectors;
+	u32 msix_vector_first_id;
+
+	/* Max MTU for function or device */
+	u32 max_mtu;
+
+	/* WOL related */
+	u32 num_wol_proxy_fltr;
+	u32 wol_proxy_vsi_seid;
+
+	/* LED/SDP pin count */
+	u32 led_pin_num;
+	u32 sdp_pin_num;
+
+	/* LED/SDP - Supports up to 12 LED pins and 8 SDP signals */
+#define IXGBE_MAX_SUPPORTED_GPIO_LED	12
+#define IXGBE_MAX_SUPPORTED_GPIO_SDP	8
+	u8 led[IXGBE_MAX_SUPPORTED_GPIO_LED];
+	u8 sdp[IXGBE_MAX_SUPPORTED_GPIO_SDP];
+	/* SR-IOV virtualization */
+	u8 sr_iov_1_1;			/* SR-IOV enabled */
+	/* VMDQ */
+	u8 vmdq;			/* VMDQ supported */
+
+	/* EVB capabilities */
+	u8 evb_802_1_qbg;		/* Edge Virtual Bridging */
+	u8 evb_802_1_qbh;		/* Bridge Port Extension */
+
+	u8 dcb;
+	u8 iscsi;
+	u8 ieee_1588;
+	u8 mgmt_cem;
+
+	/* WoL and APM support */
+#define IXGBE_WOL_SUPPORT_M		BIT(0)
+#define IXGBE_ACPI_PROG_MTHD_M		BIT(1)
+#define IXGBE_PROXY_SUPPORT_M		BIT(2)
+	u8 apm_wol_support;
+	u8 acpi_prog_mthd;
+	u8 proxy_support;
+	bool nvm_update_pending_nvm;
+	bool nvm_update_pending_orom;
+	bool nvm_update_pending_netlist;
+#define IXGBE_NVM_PENDING_NVM_IMAGE		BIT(0)
+#define IXGBE_NVM_PENDING_OROM			BIT(1)
+#define IXGBE_NVM_PENDING_NETLIST		BIT(2)
+	bool sec_rev_disabled;
+	bool update_disabled;
+	bool nvm_unified_update;
+	bool netlist_auth;
+#define IXGBE_NVM_MGMT_SEC_REV_DISABLED		BIT(0)
+#define IXGBE_NVM_MGMT_UPDATE_DISABLED		BIT(1)
+#define IXGBE_NVM_MGMT_UNIFIED_UPD_SUPPORT	BIT(3)
+#define IXGBE_NVM_MGMT_NETLIST_AUTH_SUPPORT	BIT(5)
+	bool no_drop_policy_support;
+	/* PCIe reset avoidance */
+	bool pcie_reset_avoidance; /* false: not supported, true: supported */
+	/* Post update reset restriction */
+	bool reset_restrict_support; /* false: not supported, true: supported */
+
+	/* External topology device images within the NVM */
+#define IXGBE_EXT_TOPO_DEV_IMG_COUNT	4
+	u32 ext_topo_dev_img_ver_high[IXGBE_EXT_TOPO_DEV_IMG_COUNT];
+	u32 ext_topo_dev_img_ver_low[IXGBE_EXT_TOPO_DEV_IMG_COUNT];
+	u8 ext_topo_dev_img_part_num[IXGBE_EXT_TOPO_DEV_IMG_COUNT];
+#define IXGBE_EXT_TOPO_DEV_IMG_PART_NUM_S	8
+#define IXGBE_EXT_TOPO_DEV_IMG_PART_NUM_M	GENMASK(15, 8)
+	bool ext_topo_dev_img_load_en[IXGBE_EXT_TOPO_DEV_IMG_COUNT];
+#define IXGBE_EXT_TOPO_DEV_IMG_LOAD_EN	BIT(0)
+	bool ext_topo_dev_img_prog_en[IXGBE_EXT_TOPO_DEV_IMG_COUNT];
+#define IXGBE_EXT_TOPO_DEV_IMG_PROG_EN	BIT(1)
+} __packed;
+
+/* Function specific capabilities */
+struct ixgbe_hw_func_caps {
+	u32 num_allocd_vfs;		/* Number of allocated VFs */
+	u32 vf_base_id;			/* Logical ID of the first VF */
+	u32 guar_num_vsi;
+	struct ixgbe_hw_caps common_cap;
+	bool no_drop_policy_ena;
+};
+
+/* Device wide capabilities */
+struct ixgbe_hw_dev_caps {
+	struct ixgbe_hw_caps common_cap;
+	u32 num_vfs_exposed;		/* Total number of VFs exposed */
+	u32 num_vsi_allocd_to_host;	/* Excluding EMP VSI */
+	u32 num_flow_director_fltr;	/* Number of FD filters available */
+	u32 num_funcs;
+};
+
+/* ACI event information */
+struct ixgbe_aci_event {
+	struct ixgbe_aci_desc desc;
+	u8 *msg_buf;
+	u16 msg_len;
+	u16 buf_len;
+};
+
+struct ixgbe_aci_info {
+	struct mutex lock;		/* admin command interface lock */
+	enum ixgbe_aci_err last_status;	/* last status of sent admin command */
+};
+
+/* Option ROM version information */
+struct ixgbe_orom_info {
+	u8 major;			/* Major version of OROM */
+	u8 patch;			/* Patch version of OROM */
+	u16 build;			/* Build version of OROM */
+	u32 srev;			/* Security revision */
+};
+
+/* NVM version information */
+struct ixgbe_nvm_info {
+	u32 eetrack;
+	u32 srev;
+	u8 major;
+	u8 minor;
+} __packed;
+
+/* netlist version information */
+struct ixgbe_netlist_info {
+	u32 major;			/* major high/low */
+	u32 minor;			/* minor high/low */
+	u32 type;			/* type high/low */
+	u32 rev;			/* revision high/low */
+	u32 hash;			/* SHA-1 hash word */
+	u16 cust_ver;			/* customer version */
+} __packed;
+
+/* Enumeration of possible flash banks for the NVM, OROM, and Netlist modules
+ * of the flash image.
+ */
+enum ixgbe_flash_bank {
+	IXGBE_INVALID_FLASH_BANK,
+	IXGBE_1ST_FLASH_BANK,
+	IXGBE_2ND_FLASH_BANK,
+};
+
+/* information for accessing NVM, OROM, and Netlist flash banks */
+struct ixgbe_bank_info {
+	u32 nvm_ptr;				/* Pointer to 1st NVM bank */
+	u32 nvm_size;				/* Size of NVM bank */
+	u32 orom_ptr;				/* Pointer to 1st OROM bank */
+	u32 orom_size;				/* Size of OROM bank */
+	u32 netlist_ptr;			/* Ptr to 1st Netlist bank */
+	u32 netlist_size;			/* Size of Netlist bank */
+	enum ixgbe_flash_bank nvm_bank;		/* Active NVM bank */
+	enum ixgbe_flash_bank orom_bank;	/* Active OROM bank */
+	enum ixgbe_flash_bank netlist_bank;	/* Active Netlist bank */
+};
+
+/* Flash Chip Information */
+struct ixgbe_flash_info {
+	struct ixgbe_orom_info orom;	/* Option ROM version info */
+	u32 flash_size;			/* Available flash size in bytes */
+	struct ixgbe_nvm_info nvm;	/* NVM version information */
+	struct ixgbe_netlist_info netlist;	/* Netlist version info */
+	struct ixgbe_bank_info banks;	/* Flash Bank information */
+	u16 sr_words;			/* Shadow RAM size in words */
+	u8 blank_nvm_mode;		/* is NVM empty (no FW present) */
+};
+
+#endif /* _IXGBE_TYPE_E610_H_ */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH iwl-next v9 2/7] ixgbe: Add support for E610 device capabilities detection
  2024-10-03 14:16 [PATCH iwl-next v9 0/7] ixgbe: Add support for Intel(R) E610 device Piotr Kwapulinski
  2024-10-03 14:16 ` [PATCH iwl-next v9 1/7] ixgbe: Add support for E610 FW Admin Command Interface Piotr Kwapulinski
@ 2024-10-03 14:16 ` Piotr Kwapulinski
  2024-10-17  9:46   ` Simon Horman
  2024-10-18  3:06   ` Kalesh Anakkur Purayil
  2024-10-03 14:16 ` [PATCH iwl-next v9 3/7] ixgbe: Add link management support for E610 device Piotr Kwapulinski
                   ` (4 subsequent siblings)
  6 siblings, 2 replies; 16+ messages in thread
From: Piotr Kwapulinski @ 2024-10-03 14:16 UTC (permalink / raw)
  To: intel-wired-lan
  Cc: netdev, Piotr Kwapulinski, Stefan Wegrzyn, Jedrzej Jagielski,
	Jan Sokolowski

Add low level support for E610 device capabilities detection. The
capabilities are discovered via the Admin Command Interface. Discover the
following capabilities:
- function caps: vmdq, dcb, rss, rx/tx qs, msix, nvm, orom, reset
- device caps: vsi, fdir, 1588
- phy caps

Co-developed-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
Signed-off-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
Co-developed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Signed-off-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Reviewed-by: Jan Sokolowski <jan.sokolowski@intel.com>
Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 540 ++++++++++++++++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h |  12 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |   8 +
 3 files changed, 560 insertions(+)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
index 28bd7da..3bc88df 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
@@ -493,3 +493,543 @@ void ixgbe_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res)
 		total_delay++;
 	}
 }
+
+/**
+ * ixgbe_parse_e610_caps - Parse common device/function capabilities
+ * @hw: pointer to the HW struct
+ * @caps: pointer to common capabilities structure
+ * @elem: the capability element to parse
+ * @prefix: message prefix for tracing capabilities
+ *
+ * Given a capability element, extract relevant details into the common
+ * capability structure.
+ *
+ * Return: true if the capability matches one of the common capability ids,
+ * false otherwise.
+ */
+static bool ixgbe_parse_e610_caps(struct ixgbe_hw *hw,
+				  struct ixgbe_hw_caps *caps,
+				  struct ixgbe_aci_cmd_list_caps_elem *elem,
+				  const char *prefix)
+{
+	u32 logical_id = elem->logical_id;
+	u32 phys_id = elem->phys_id;
+	u32 number = elem->number;
+	u16 cap = elem->cap;
+
+	switch (cap) {
+	case IXGBE_ACI_CAPS_VALID_FUNCTIONS:
+		caps->valid_functions = number;
+		break;
+	case IXGBE_ACI_CAPS_SRIOV:
+		caps->sr_iov_1_1 = (number == 1);
+		break;
+	case IXGBE_ACI_CAPS_VMDQ:
+		caps->vmdq = (number == 1);
+		break;
+	case IXGBE_ACI_CAPS_DCB:
+		caps->dcb = (number == 1);
+		caps->active_tc_bitmap = logical_id;
+		caps->maxtc = phys_id;
+		break;
+	case IXGBE_ACI_CAPS_RSS:
+		caps->rss_table_size = number;
+		caps->rss_table_entry_width = logical_id;
+		break;
+	case IXGBE_ACI_CAPS_RXQS:
+		caps->num_rxq = number;
+		caps->rxq_first_id = phys_id;
+		break;
+	case IXGBE_ACI_CAPS_TXQS:
+		caps->num_txq = number;
+		caps->txq_first_id = phys_id;
+		break;
+	case IXGBE_ACI_CAPS_MSIX:
+		caps->num_msix_vectors = number;
+		caps->msix_vector_first_id = phys_id;
+		break;
+	case IXGBE_ACI_CAPS_NVM_VER:
+		break;
+	case IXGBE_ACI_CAPS_MAX_MTU:
+		caps->max_mtu = number;
+		break;
+	case IXGBE_ACI_CAPS_PCIE_RESET_AVOIDANCE:
+		caps->pcie_reset_avoidance = (number > 0);
+		break;
+	case IXGBE_ACI_CAPS_POST_UPDATE_RESET_RESTRICT:
+		caps->reset_restrict_support = (number == 1);
+		break;
+	case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG0:
+	case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG1:
+	case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG2:
+	case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG3:
+	{
+		u8 index = cap - IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG0;
+
+		caps->ext_topo_dev_img_ver_high[index] = number;
+		caps->ext_topo_dev_img_ver_low[index] = logical_id;
+		caps->ext_topo_dev_img_part_num[index] =
+			FIELD_GET(IXGBE_EXT_TOPO_DEV_IMG_PART_NUM_M, phys_id);
+		caps->ext_topo_dev_img_load_en[index] =
+			(phys_id & IXGBE_EXT_TOPO_DEV_IMG_LOAD_EN) != 0;
+		caps->ext_topo_dev_img_prog_en[index] =
+			(phys_id & IXGBE_EXT_TOPO_DEV_IMG_PROG_EN) != 0;
+		break;
+	}
+	default:
+		/* Not one of the recognized common capabilities */
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * ixgbe_parse_valid_functions_cap - Parse IXGBE_ACI_CAPS_VALID_FUNCTIONS caps
+ * @hw: pointer to the HW struct
+ * @dev_p: pointer to device capabilities structure
+ * @cap: capability element to parse
+ *
+ * Parse IXGBE_ACI_CAPS_VALID_FUNCTIONS for device capabilities.
+ */
+static void
+ixgbe_parse_valid_functions_cap(struct ixgbe_hw *hw,
+				struct ixgbe_hw_dev_caps *dev_p,
+				struct ixgbe_aci_cmd_list_caps_elem *cap)
+{
+	u32 number = cap->number;
+
+	dev_p->num_funcs = hweight32(number);
+}
+
+/**
+ * ixgbe_parse_vf_dev_caps - Parse IXGBE_ACI_CAPS_VF device caps
+ * @hw: pointer to the HW struct
+ * @dev_p: pointer to device capabilities structure
+ * @cap: capability element to parse
+ *
+ * Parse IXGBE_ACI_CAPS_VF for device capabilities.
+ */
+static void ixgbe_parse_vf_dev_caps(struct ixgbe_hw *hw,
+				    struct ixgbe_hw_dev_caps *dev_p,
+				    struct ixgbe_aci_cmd_list_caps_elem *cap)
+{
+	u32 number = cap->number;
+
+	dev_p->num_vfs_exposed = number;
+}
+
+/**
+ * ixgbe_parse_vsi_dev_caps - Parse IXGBE_ACI_CAPS_VSI device caps
+ * @hw: pointer to the HW struct
+ * @dev_p: pointer to device capabilities structure
+ * @cap: capability element to parse
+ *
+ * Parse IXGBE_ACI_CAPS_VSI for device capabilities.
+ */
+static void ixgbe_parse_vsi_dev_caps(struct ixgbe_hw *hw,
+				     struct ixgbe_hw_dev_caps *dev_p,
+				     struct ixgbe_aci_cmd_list_caps_elem *cap)
+{
+	u32 number = cap->number;
+
+	dev_p->num_vsi_allocd_to_host = number;
+}
+
+/**
+ * ixgbe_parse_fdir_dev_caps - Parse IXGBE_ACI_CAPS_FD device caps
+ * @hw: pointer to the HW struct
+ * @dev_p: pointer to device capabilities structure
+ * @cap: capability element to parse
+ *
+ * Parse IXGBE_ACI_CAPS_FD for device capabilities.
+ */
+static void ixgbe_parse_fdir_dev_caps(struct ixgbe_hw *hw,
+				      struct ixgbe_hw_dev_caps *dev_p,
+				      struct ixgbe_aci_cmd_list_caps_elem *cap)
+{
+	u32 number = cap->number;
+
+	dev_p->num_flow_director_fltr = number;
+}
+
+/**
+ * ixgbe_parse_dev_caps - Parse device capabilities
+ * @hw: pointer to the HW struct
+ * @dev_p: pointer to device capabilities structure
+ * @buf: buffer containing the device capability records
+ * @cap_count: the number of capabilities
+ *
+ * Helper device to parse device (0x000B) capabilities list. For
+ * capabilities shared between device and function, this relies on
+ * ixgbe_parse_e610_caps.
+ *
+ * Loop through the list of provided capabilities and extract the relevant
+ * data into the device capabilities structured.
+ */
+static void ixgbe_parse_dev_caps(struct ixgbe_hw *hw,
+				 struct ixgbe_hw_dev_caps *dev_p,
+				 void *buf, u32 cap_count)
+{
+	struct ixgbe_aci_cmd_list_caps_elem *cap_resp;
+	u32 i;
+
+	cap_resp = (struct ixgbe_aci_cmd_list_caps_elem *)buf;
+
+	memset(dev_p, 0, sizeof(*dev_p));
+
+	for (i = 0; i < cap_count; i++) {
+		u16 cap = cap_resp[i].cap;
+
+		ixgbe_parse_e610_caps(hw, &dev_p->common_cap, &cap_resp[i],
+				      "dev caps");
+
+		switch (cap) {
+		case IXGBE_ACI_CAPS_VALID_FUNCTIONS:
+			ixgbe_parse_valid_functions_cap(hw, dev_p,
+							&cap_resp[i]);
+			break;
+		case IXGBE_ACI_CAPS_VF:
+			ixgbe_parse_vf_dev_caps(hw, dev_p, &cap_resp[i]);
+			break;
+		case IXGBE_ACI_CAPS_VSI:
+			ixgbe_parse_vsi_dev_caps(hw, dev_p, &cap_resp[i]);
+			break;
+		case  IXGBE_ACI_CAPS_FD:
+			ixgbe_parse_fdir_dev_caps(hw, dev_p, &cap_resp[i]);
+			break;
+		default:
+			/* Don't list common capabilities as unknown */
+			break;
+		}
+	}
+}
+
+/**
+ * ixgbe_parse_vf_func_caps - Parse IXGBE_ACI_CAPS_VF function caps
+ * @hw: pointer to the HW struct
+ * @func_p: pointer to function capabilities structure
+ * @cap: pointer to the capability element to parse
+ *
+ * Extract function capabilities for IXGBE_ACI_CAPS_VF.
+ */
+static void ixgbe_parse_vf_func_caps(struct ixgbe_hw *hw,
+				     struct ixgbe_hw_func_caps *func_p,
+				     struct ixgbe_aci_cmd_list_caps_elem *cap)
+{
+	u32 logical_id = cap->logical_id;
+	u32 number = cap->number;
+
+	func_p->num_allocd_vfs = number;
+	func_p->vf_base_id = logical_id;
+}
+
+/**
+ * ixgbe_get_num_per_func - determine number of resources per PF
+ * @hw: pointer to the HW structure
+ * @max: value to be evenly split between each PF
+ *
+ * Determine the number of valid functions by going through the bitmap returned
+ * from parsing capabilities and use this to calculate the number of resources
+ * per PF based on the max value passed in.
+ *
+ * Return: the number of resources per PF or 0, if no PH are available.
+ */
+static u32 ixgbe_get_num_per_func(struct ixgbe_hw *hw, u32 max)
+{
+#define IXGBE_CAPS_VALID_FUNCS_M	GENMASK(7, 0)
+	u8 funcs = hweight8(hw->dev_caps.common_cap.valid_functions &
+			    IXGBE_CAPS_VALID_FUNCS_M);
+
+	return funcs ? (max / funcs) : 0;
+}
+
+/**
+ * ixgbe_parse_vsi_func_caps - Parse IXGBE_ACI_CAPS_VSI function caps
+ * @hw: pointer to the HW struct
+ * @func_p: pointer to function capabilities structure
+ * @cap: pointer to the capability element to parse
+ *
+ * Extract function capabilities for IXGBE_ACI_CAPS_VSI.
+ */
+static void ixgbe_parse_vsi_func_caps(struct ixgbe_hw *hw,
+				      struct ixgbe_hw_func_caps *func_p,
+				      struct ixgbe_aci_cmd_list_caps_elem *cap)
+{
+	func_p->guar_num_vsi = ixgbe_get_num_per_func(hw, IXGBE_MAX_VSI);
+}
+
+/**
+ * ixgbe_parse_func_caps - Parse function capabilities
+ * @hw: pointer to the HW struct
+ * @func_p: pointer to function capabilities structure
+ * @buf: buffer containing the function capability records
+ * @cap_count: the number of capabilities
+ *
+ * Helper function to parse function (0x000A) capabilities list. For
+ * capabilities shared between device and function, this relies on
+ * ixgbe_parse_e610_caps.
+ *
+ * Loop through the list of provided capabilities and extract the relevant
+ * data into the function capabilities structured.
+ */
+static void ixgbe_parse_func_caps(struct ixgbe_hw *hw,
+				  struct ixgbe_hw_func_caps *func_p,
+				  void *buf, u32 cap_count)
+{
+	struct ixgbe_aci_cmd_list_caps_elem *cap_resp;
+	u32 i;
+
+	cap_resp = (struct ixgbe_aci_cmd_list_caps_elem *)buf;
+
+	memset(func_p, 0, sizeof(*func_p));
+
+	for (i = 0; i < cap_count; i++) {
+		u16 cap = cap_resp[i].cap;
+
+		ixgbe_parse_e610_caps(hw, &func_p->common_cap,
+				      &cap_resp[i], "func caps");
+
+		switch (cap) {
+		case IXGBE_ACI_CAPS_VF:
+			ixgbe_parse_vf_func_caps(hw, func_p, &cap_resp[i]);
+			break;
+		case IXGBE_ACI_CAPS_VSI:
+			ixgbe_parse_vsi_func_caps(hw, func_p, &cap_resp[i]);
+			break;
+		default:
+			/* Don't list common capabilities as unknown */
+			break;
+		}
+	}
+}
+
+/**
+ * ixgbe_aci_list_caps - query function/device capabilities
+ * @hw: pointer to the HW struct
+ * @buf: a buffer to hold the capabilities
+ * @buf_size: size of the buffer
+ * @cap_count: if not NULL, set to the number of capabilities reported
+ * @opc: capabilities type to discover, device or function
+ *
+ * Get the function (0x000A) or device (0x000B) capabilities description from
+ * firmware and store it in the buffer.
+ *
+ * If the cap_count pointer is not NULL, then it is set to the number of
+ * capabilities firmware will report. Note that if the buffer size is too
+ * small, it is possible the command will return -ENOMEM. The
+ * cap_count will still be updated in this case. It is recommended that the
+ * buffer size be set to IXGBE_ACI_MAX_BUFFER_SIZE (the largest possible
+ * buffer that firmware could return) to avoid this.
+ *
+ * Return: the exit code of the operation.
+ * Exit code of -ENOMEM means the buffer size is too small.
+ */
+int ixgbe_aci_list_caps(struct ixgbe_hw *hw, void *buf, u16 buf_size,
+			u32 *cap_count, enum ixgbe_aci_opc opc)
+{
+	struct ixgbe_aci_cmd_list_caps *cmd;
+	struct ixgbe_aci_desc desc;
+	int err;
+
+	cmd = &desc.params.get_cap;
+
+	if (opc != ixgbe_aci_opc_list_func_caps &&
+	    opc != ixgbe_aci_opc_list_dev_caps)
+		return -EINVAL;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, opc);
+	err = ixgbe_aci_send_cmd(hw, &desc, buf, buf_size);
+
+	if (cap_count)
+		*cap_count = cmd->count;
+
+	return err;
+}
+
+/**
+ * ixgbe_discover_dev_caps - Read and extract device capabilities
+ * @hw: pointer to the hardware structure
+ * @dev_caps: pointer to device capabilities structure
+ *
+ * Read the device capabilities and extract them into the dev_caps structure
+ * for later use.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_discover_dev_caps(struct ixgbe_hw *hw,
+			    struct ixgbe_hw_dev_caps *dev_caps)
+{
+	u8 *cbuf __free(kfree);
+	u32 cap_count;
+	int err;
+
+	cbuf = kzalloc(IXGBE_ACI_MAX_BUFFER_SIZE, GFP_KERNEL);
+	if (!cbuf)
+		return -ENOMEM;
+	/* Although the driver doesn't know the number of capabilities the
+	 * device will return, we can simply send a 4KB buffer, the maximum
+	 * possible size that firmware can return.
+	 */
+	cap_count = IXGBE_ACI_MAX_BUFFER_SIZE /
+		    sizeof(struct ixgbe_aci_cmd_list_caps_elem);
+
+	err = ixgbe_aci_list_caps(hw, cbuf, IXGBE_ACI_MAX_BUFFER_SIZE,
+				  &cap_count,
+				  ixgbe_aci_opc_list_dev_caps);
+	if (err)
+		return err;
+
+	ixgbe_parse_dev_caps(hw, dev_caps, cbuf, cap_count);
+
+	return 0;
+}
+
+/**
+ * ixgbe_discover_func_caps - Read and extract function capabilities
+ * @hw: pointer to the hardware structure
+ * @func_caps: pointer to function capabilities structure
+ *
+ * Read the function capabilities and extract them into the func_caps structure
+ * for later use.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_discover_func_caps(struct ixgbe_hw *hw,
+			     struct ixgbe_hw_func_caps *func_caps)
+{
+	u8 *cbuf __free(kfree);
+	u32 cap_count;
+	int err;
+
+	cbuf = kzalloc(IXGBE_ACI_MAX_BUFFER_SIZE, GFP_KERNEL);
+	if (!cbuf)
+		return -ENOMEM;
+
+	/* Although the driver doesn't know the number of capabilities the
+	 * device will return, we can simply send a 4KB buffer, the maximum
+	 * possible size that firmware can return.
+	 */
+	cap_count = IXGBE_ACI_MAX_BUFFER_SIZE /
+		    sizeof(struct ixgbe_aci_cmd_list_caps_elem);
+
+	err = ixgbe_aci_list_caps(hw, cbuf, IXGBE_ACI_MAX_BUFFER_SIZE,
+				  &cap_count,
+				  ixgbe_aci_opc_list_func_caps);
+	if (err)
+		return err;
+
+	ixgbe_parse_func_caps(hw, func_caps, cbuf, cap_count);
+
+	return 0;
+}
+
+/**
+ * ixgbe_get_caps - get info about the HW
+ * @hw: pointer to the hardware structure
+ *
+ * Retrieve both device and function capabilities.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_get_caps(struct ixgbe_hw *hw)
+{
+	int err;
+
+	err = ixgbe_discover_dev_caps(hw, &hw->dev_caps);
+	if (err)
+		return err;
+
+	return ixgbe_discover_func_caps(hw, &hw->func_caps);
+}
+
+/**
+ * ixgbe_aci_disable_rxen - disable RX
+ * @hw: pointer to the HW struct
+ *
+ * Request a safe disable of Receive Enable using ACI command (0x000C).
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_aci_disable_rxen(struct ixgbe_hw *hw)
+{
+	struct ixgbe_aci_cmd_disable_rxen *cmd;
+	struct ixgbe_aci_desc desc;
+
+	cmd = &desc.params.disable_rxen;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_disable_rxen);
+
+	cmd->lport_num = hw->bus.func;
+
+	return ixgbe_aci_send_cmd(hw, &desc, NULL, 0);
+}
+
+/**
+ * ixgbe_aci_get_phy_caps - returns PHY capabilities
+ * @hw: pointer to the HW struct
+ * @qual_mods: report qualified modules
+ * @report_mode: report mode capabilities
+ * @pcaps: structure for PHY capabilities to be filled
+ *
+ * Returns the various PHY capabilities supported on the Port
+ * using ACI command (0x0600).
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_aci_get_phy_caps(struct ixgbe_hw *hw, bool qual_mods, u8 report_mode,
+			   struct ixgbe_aci_cmd_get_phy_caps_data *pcaps)
+{
+	struct ixgbe_aci_cmd_get_phy_caps *cmd;
+	u16 pcaps_size = sizeof(*pcaps);
+	struct ixgbe_aci_desc desc;
+	int err;
+
+	cmd = &desc.params.get_phy;
+
+	if (!pcaps || (report_mode & ~IXGBE_ACI_REPORT_MODE_M))
+		return -EINVAL;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_phy_caps);
+
+	if (qual_mods)
+		cmd->param0 |= IXGBE_ACI_GET_PHY_RQM;
+
+	cmd->param0 |= report_mode;
+	err = ixgbe_aci_send_cmd(hw, &desc, pcaps, pcaps_size);
+
+	if (!err && report_mode == IXGBE_ACI_REPORT_TOPO_CAP_MEDIA) {
+		hw->phy.phy_type_low = pcaps->phy_type_low;
+		hw->phy.phy_type_high = pcaps->phy_type_high;
+		memcpy(hw->link.link_info.module_type, &pcaps->module_type,
+		       sizeof(hw->link.link_info.module_type));
+	}
+
+	return err;
+}
+
+/**
+ * ixgbe_copy_phy_caps_to_cfg - Copy PHY ability data to configuration data
+ * @caps: PHY ability structure to copy data from
+ * @cfg: PHY configuration structure to copy data to
+ *
+ * Helper function to copy data from PHY capabilities data structure
+ * to PHY configuration data structure
+ */
+void ixgbe_copy_phy_caps_to_cfg(struct ixgbe_aci_cmd_get_phy_caps_data *caps,
+				struct ixgbe_aci_cmd_set_phy_cfg_data *cfg)
+{
+	if (!caps || !cfg)
+		return;
+
+	memset(cfg, 0, sizeof(*cfg));
+	cfg->phy_type_low = caps->phy_type_low;
+	cfg->phy_type_high = caps->phy_type_high;
+	cfg->caps = caps->caps;
+	cfg->low_power_ctrl_an = caps->low_power_ctrl_an;
+	cfg->eee_cap = caps->eee_cap;
+	cfg->eeer_value = caps->eeer_value;
+	cfg->link_fec_opt = caps->link_fec_options;
+	cfg->module_compliance_enforcement =
+		caps->module_compliance_enforcement;
+}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
index 18b831b..5c5a676 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
@@ -15,5 +15,17 @@ void ixgbe_fill_dflt_direct_cmd_desc(struct ixgbe_aci_desc *desc, u16 opcode);
 int ixgbe_acquire_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res,
 		      enum ixgbe_aci_res_access_type access, u32 timeout);
 void ixgbe_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res);
+int ixgbe_aci_list_caps(struct ixgbe_hw *hw, void *buf, u16 buf_size,
+			u32 *cap_count, enum ixgbe_aci_opc opc);
+int ixgbe_discover_dev_caps(struct ixgbe_hw *hw,
+			    struct ixgbe_hw_dev_caps *dev_caps);
+int ixgbe_discover_func_caps(struct ixgbe_hw *hw,
+			     struct ixgbe_hw_func_caps *func_caps);
+int ixgbe_get_caps(struct ixgbe_hw *hw);
+int ixgbe_aci_disable_rxen(struct ixgbe_hw *hw);
+int ixgbe_aci_get_phy_caps(struct ixgbe_hw *hw, bool qual_mods, u8 report_mode,
+			   struct ixgbe_aci_cmd_get_phy_caps_data *pcaps);
+void ixgbe_copy_phy_caps_to_cfg(struct ixgbe_aci_cmd_get_phy_caps_data *caps,
+				struct ixgbe_aci_cmd_set_phy_cfg_data *cfg);
 
 #endif /* _IXGBE_E610_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 8b8404d..0302a21 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -43,6 +43,7 @@
 #include "ixgbe.h"
 #include "ixgbe_common.h"
 #include "ixgbe_dcb_82599.h"
+#include "ixgbe_e610.h"
 #include "ixgbe_phy.h"
 #include "ixgbe_sriov.h"
 #include "ixgbe_model.h"
@@ -10932,6 +10933,13 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	if (err)
 		goto err_sw_init;
 
+	if (adapter->hw.mac.type == ixgbe_mac_e610) {
+		err = ixgbe_get_caps(&adapter->hw);
+		if (err)
+			dev_err(&pdev->dev,
+				"ixgbe_get_caps failed %d\n", err);
+	}
+
 	if (adapter->hw.mac.type == ixgbe_mac_82599EB)
 		adapter->flags2 |= IXGBE_FLAG2_AUTO_DISABLE_VF;
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH iwl-next v9 3/7] ixgbe: Add link management support for E610 device
  2024-10-03 14:16 [PATCH iwl-next v9 0/7] ixgbe: Add support for Intel(R) E610 device Piotr Kwapulinski
  2024-10-03 14:16 ` [PATCH iwl-next v9 1/7] ixgbe: Add support for E610 FW Admin Command Interface Piotr Kwapulinski
  2024-10-03 14:16 ` [PATCH iwl-next v9 2/7] ixgbe: Add support for E610 device capabilities detection Piotr Kwapulinski
@ 2024-10-03 14:16 ` Piotr Kwapulinski
  2024-10-17  9:46   ` Simon Horman
  2024-10-17 13:26   ` Kalesh Anakkur Purayil
  2024-10-03 14:16 ` [PATCH iwl-next v9 4/7] ixgbe: Add support for NVM handling in " Piotr Kwapulinski
                   ` (3 subsequent siblings)
  6 siblings, 2 replies; 16+ messages in thread
From: Piotr Kwapulinski @ 2024-10-03 14:16 UTC (permalink / raw)
  To: intel-wired-lan
  Cc: netdev, Piotr Kwapulinski, Stefan Wegrzyn, Jedrzej Jagielski,
	Jan Glaza

Add low level link management support for E610 device. Link management
operations are handled via the Admin Command Interface. Add the following
link management operations:
- get link capabilities
- set up link
- get media type
- get link status, link status events
- link power management

Co-developed-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
Signed-off-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
Co-developed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Signed-off-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Reviewed-by: Jan Glaza <jan.glaza@intel.com>
Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 1091 +++++++++++++++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h |   32 +
 .../ethernet/intel/ixgbe/ixgbe_type_e610.h    |    1 +
 3 files changed, 1124 insertions(+)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
index 3bc88df..c0c740f 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
@@ -1033,3 +1033,1094 @@ void ixgbe_copy_phy_caps_to_cfg(struct ixgbe_aci_cmd_get_phy_caps_data *caps,
 	cfg->module_compliance_enforcement =
 		caps->module_compliance_enforcement;
 }
+
+/**
+ * ixgbe_aci_set_phy_cfg - set PHY configuration
+ * @hw: pointer to the HW struct
+ * @cfg: structure with PHY configuration data to be set
+ *
+ * Set the various PHY configuration parameters supported on the Port
+ * using ACI command (0x0601).
+ * One or more of the Set PHY config parameters may be ignored in an MFP
+ * mode as the PF may not have the privilege to set some of the PHY Config
+ * parameters.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_aci_set_phy_cfg(struct ixgbe_hw *hw,
+			  struct ixgbe_aci_cmd_set_phy_cfg_data *cfg)
+{
+	struct ixgbe_aci_desc desc;
+	int err;
+
+	if (!cfg)
+		return -EINVAL;
+
+	/* Ensure that only valid bits of cfg->caps can be turned on. */
+	cfg->caps &= IXGBE_ACI_PHY_ENA_VALID_MASK;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_set_phy_cfg);
+	desc.params.set_phy.lport_num = hw->bus.func;
+	desc.flags |= IXGBE_ACI_FLAG_RD;
+
+	err = ixgbe_aci_send_cmd(hw, &desc, cfg, sizeof(*cfg));
+
+	if (!err)
+		hw->phy.curr_user_phy_cfg = *cfg;
+
+	return err;
+}
+
+/**
+ * ixgbe_aci_set_link_restart_an - set up link and restart AN
+ * @hw: pointer to the HW struct
+ * @ena_link: if true: enable link, if false: disable link
+ *
+ * Function sets up the link and restarts the Auto-Negotiation over the link.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_aci_set_link_restart_an(struct ixgbe_hw *hw, bool ena_link)
+{
+	struct ixgbe_aci_cmd_restart_an *cmd;
+	struct ixgbe_aci_desc desc;
+
+	cmd = &desc.params.restart_an;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_restart_an);
+
+	cmd->cmd_flags = IXGBE_ACI_RESTART_AN_LINK_RESTART;
+	cmd->lport_num = hw->bus.func;
+	if (ena_link)
+		cmd->cmd_flags |= IXGBE_ACI_RESTART_AN_LINK_ENABLE;
+	else
+		cmd->cmd_flags &= ~IXGBE_ACI_RESTART_AN_LINK_ENABLE;
+
+	return ixgbe_aci_send_cmd(hw, &desc, NULL, 0);
+}
+
+/**
+ * ixgbe_is_media_cage_present - check if media cage is present
+ * @hw: pointer to the HW struct
+ *
+ * Identify presence of media cage using the ACI command (0x06E0).
+ *
+ * Return: true if media cage is present, else false. If no cage, then
+ * media type is backplane or BASE-T.
+ */
+static bool ixgbe_is_media_cage_present(struct ixgbe_hw *hw)
+{
+	struct ixgbe_aci_cmd_get_link_topo *cmd;
+	struct ixgbe_aci_desc desc;
+
+	cmd = &desc.params.get_link_topo;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_link_topo);
+
+	cmd->addr.topo_params.node_type_ctx =
+		FIELD_PREP(IXGBE_ACI_LINK_TOPO_NODE_CTX_M,
+			   IXGBE_ACI_LINK_TOPO_NODE_CTX_PORT);
+
+	/* Set node type. */
+	cmd->addr.topo_params.node_type_ctx |=
+		FIELD_PREP(IXGBE_ACI_LINK_TOPO_NODE_TYPE_M,
+			   IXGBE_ACI_LINK_TOPO_NODE_TYPE_CAGE);
+
+	/* Node type cage can be used to determine if cage is present. If AQC
+	 * returns error (ENOENT), then no cage present. If no cage present then
+	 * connection type is backplane or BASE-T.
+	 */
+	return ixgbe_aci_get_netlist_node(hw, cmd, NULL, NULL);
+}
+
+/**
+ * ixgbe_get_media_type_from_phy_type - Gets media type based on phy type
+ * @hw: pointer to the HW struct
+ *
+ * Try to identify the media type based on the phy type.
+ * If more than one media type, the ixgbe_media_type_unknown is returned.
+ * First, phy_type_low is checked, then phy_type_high.
+ * If none are identified, the ixgbe_media_type_unknown is returned
+ *
+ * Return: type of a media based on phy type in form of enum.
+ */
+static enum ixgbe_media_type
+ixgbe_get_media_type_from_phy_type(struct ixgbe_hw *hw)
+{
+	struct ixgbe_link_status *hw_link_info;
+
+	if (!hw)
+		return ixgbe_media_type_unknown;
+
+	hw_link_info = &hw->link.link_info;
+	if (hw_link_info->phy_type_low && hw_link_info->phy_type_high)
+		/* If more than one media type is selected, report unknown */
+		return ixgbe_media_type_unknown;
+
+	if (hw_link_info->phy_type_low) {
+		/* 1G SGMII is a special case where some DA cable PHYs
+		 * may show this as an option when it really shouldn't
+		 * be since SGMII is meant to be between a MAC and a PHY
+		 * in a backplane. Try to detect this case and handle it
+		 */
+		if (hw_link_info->phy_type_low == IXGBE_PHY_TYPE_LOW_1G_SGMII &&
+		    (hw_link_info->module_type[IXGBE_ACI_MOD_TYPE_IDENT] ==
+		    IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_ACTIVE ||
+		    hw_link_info->module_type[IXGBE_ACI_MOD_TYPE_IDENT] ==
+		    IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_PASSIVE))
+			return ixgbe_media_type_da;
+
+		switch (hw_link_info->phy_type_low) {
+		case IXGBE_PHY_TYPE_LOW_1000BASE_SX:
+		case IXGBE_PHY_TYPE_LOW_1000BASE_LX:
+		case IXGBE_PHY_TYPE_LOW_10GBASE_SR:
+		case IXGBE_PHY_TYPE_LOW_10GBASE_LR:
+		case IXGBE_PHY_TYPE_LOW_25GBASE_SR:
+		case IXGBE_PHY_TYPE_LOW_25GBASE_LR:
+			return ixgbe_media_type_fiber;
+		case IXGBE_PHY_TYPE_LOW_10G_SFI_AOC_ACC:
+		case IXGBE_PHY_TYPE_LOW_25G_AUI_AOC_ACC:
+			return ixgbe_media_type_fiber;
+		case IXGBE_PHY_TYPE_LOW_100BASE_TX:
+		case IXGBE_PHY_TYPE_LOW_1000BASE_T:
+		case IXGBE_PHY_TYPE_LOW_2500BASE_T:
+		case IXGBE_PHY_TYPE_LOW_5GBASE_T:
+		case IXGBE_PHY_TYPE_LOW_10GBASE_T:
+		case IXGBE_PHY_TYPE_LOW_25GBASE_T:
+			return ixgbe_media_type_copper;
+		case IXGBE_PHY_TYPE_LOW_10G_SFI_DA:
+		case IXGBE_PHY_TYPE_LOW_25GBASE_CR:
+		case IXGBE_PHY_TYPE_LOW_25GBASE_CR_S:
+		case IXGBE_PHY_TYPE_LOW_25GBASE_CR1:
+			return ixgbe_media_type_da;
+		case IXGBE_PHY_TYPE_LOW_25G_AUI_C2C:
+			if (ixgbe_is_media_cage_present(hw))
+				return ixgbe_media_type_aui;
+			fallthrough;
+		case IXGBE_PHY_TYPE_LOW_1000BASE_KX:
+		case IXGBE_PHY_TYPE_LOW_2500BASE_KX:
+		case IXGBE_PHY_TYPE_LOW_2500BASE_X:
+		case IXGBE_PHY_TYPE_LOW_5GBASE_KR:
+		case IXGBE_PHY_TYPE_LOW_10GBASE_KR_CR1:
+		case IXGBE_PHY_TYPE_LOW_10G_SFI_C2C:
+		case IXGBE_PHY_TYPE_LOW_25GBASE_KR:
+		case IXGBE_PHY_TYPE_LOW_25GBASE_KR1:
+		case IXGBE_PHY_TYPE_LOW_25GBASE_KR_S:
+			return ixgbe_media_type_backplane;
+		}
+	} else {
+		switch (hw_link_info->phy_type_high) {
+		case IXGBE_PHY_TYPE_HIGH_10BASE_T:
+			return ixgbe_media_type_copper;
+		}
+	}
+	return ixgbe_media_type_unknown;
+}
+
+/**
+ * ixgbe_update_link_info - update status of the HW network link
+ * @hw: pointer to the HW struct
+ *
+ * Update the status of the HW network link.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_update_link_info(struct ixgbe_hw *hw)
+{
+	struct ixgbe_link_status *li;
+	int err;
+
+	if (!hw)
+		return -EINVAL;
+
+	li = &hw->link.link_info;
+
+	err = ixgbe_aci_get_link_info(hw, true, NULL);
+	if (err)
+		return err;
+
+	if (li->link_info & IXGBE_ACI_MEDIA_AVAILABLE) {
+		struct ixgbe_aci_cmd_get_phy_caps_data __free(kfree) *pcaps;
+
+		pcaps =	kzalloc(sizeof(*pcaps), GFP_KERNEL);
+		if (!pcaps)
+			return -ENOMEM;
+
+		err = ixgbe_aci_get_phy_caps(hw, false,
+					     IXGBE_ACI_REPORT_TOPO_CAP_MEDIA,
+					     pcaps);
+
+		if (!err)
+			memcpy(li->module_type, &pcaps->module_type,
+			       sizeof(li->module_type));
+	}
+
+	return err;
+}
+
+/**
+ * ixgbe_get_link_status - get status of the HW network link
+ * @hw: pointer to the HW struct
+ * @link_up: pointer to bool (true/false = linkup/linkdown)
+ *
+ * Variable link_up is true if link is up, false if link is down.
+ * The variable link_up is invalid if status is non zero. As a
+ * result of this call, link status reporting becomes enabled
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_get_link_status(struct ixgbe_hw *hw, bool *link_up)
+{
+	if (!hw || !link_up)
+		return -EINVAL;
+
+	if (hw->link.get_link_info) {
+		int err = ixgbe_update_link_info(hw);
+
+		if (err)
+			return err;
+	}
+
+	*link_up = hw->link.link_info.link_info & IXGBE_ACI_LINK_UP;
+
+	return 0;
+}
+
+/**
+ * ixgbe_aci_get_link_info - get the link status
+ * @hw: pointer to the HW struct
+ * @ena_lse: enable/disable LinkStatusEvent reporting
+ * @link: pointer to link status structure - optional
+ *
+ * Get the current Link Status using ACI command (0x607).
+ * The current link can be optionally provided to update
+ * the status.
+ *
+ * Return: the link status of the adapter.
+ */
+int ixgbe_aci_get_link_info(struct ixgbe_hw *hw, bool ena_lse,
+			    struct ixgbe_link_status *link)
+{
+	struct ixgbe_aci_cmd_get_link_status_data link_data = { 0 };
+	struct ixgbe_aci_cmd_get_link_status *resp;
+	struct ixgbe_link_status *li_old, *li;
+	struct ixgbe_fc_info *hw_fc_info;
+	struct ixgbe_aci_desc desc;
+	bool tx_pause, rx_pause;
+	u8 cmd_flags;
+	int err;
+
+	if (!hw)
+		return -EINVAL;
+
+	li_old = &hw->link.link_info_old;
+	li = &hw->link.link_info;
+	hw_fc_info = &hw->fc;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_link_status);
+	cmd_flags = (ena_lse) ? IXGBE_ACI_LSE_ENA : IXGBE_ACI_LSE_DIS;
+	resp = &desc.params.get_link_status;
+	resp->cmd_flags = cmd_flags;
+	resp->lport_num = hw->bus.func;
+
+	err = ixgbe_aci_send_cmd(hw, &desc, &link_data, sizeof(link_data));
+
+	if (err)
+		return err;
+
+	/* Save off old link status information. */
+	*li_old = *li;
+
+	/* Update current link status information. */
+	li->link_speed = link_data.link_speed;
+	li->phy_type_low = link_data.phy_type_low;
+	li->phy_type_high = link_data.phy_type_high;
+	li->link_info = link_data.link_info;
+	li->link_cfg_err = link_data.link_cfg_err;
+	li->an_info = link_data.an_info;
+	li->ext_info = link_data.ext_info;
+	li->max_frame_size = link_data.max_frame_size;
+	li->fec_info = link_data.cfg & IXGBE_ACI_FEC_MASK;
+	li->topo_media_conflict = link_data.topo_media_conflict;
+	li->pacing = link_data.cfg & (IXGBE_ACI_CFG_PACING_M |
+				      IXGBE_ACI_CFG_PACING_TYPE_M);
+
+	/* Update fc info. */
+	tx_pause = !!(link_data.an_info & IXGBE_ACI_LINK_PAUSE_TX);
+	rx_pause = !!(link_data.an_info & IXGBE_ACI_LINK_PAUSE_RX);
+	if (tx_pause && rx_pause)
+		hw_fc_info->current_mode = ixgbe_fc_full;
+	else if (tx_pause)
+		hw_fc_info->current_mode = ixgbe_fc_tx_pause;
+	else if (rx_pause)
+		hw_fc_info->current_mode = ixgbe_fc_rx_pause;
+	else
+		hw_fc_info->current_mode = ixgbe_fc_none;
+
+	li->lse_ena = !!(resp->cmd_flags & IXGBE_ACI_LSE_IS_ENABLED);
+
+	/* Save link status information. */
+	if (link)
+		*link = *li;
+
+	/* Flag cleared so calling functions don't call AQ again. */
+	hw->link.get_link_info = false;
+
+	return 0;
+}
+
+/**
+ * ixgbe_aci_set_event_mask - set event mask
+ * @hw: pointer to the HW struct
+ * @port_num: port number of the physical function
+ * @mask: event mask to be set
+ *
+ * Set the event mask using ACI command (0x0613).
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_aci_set_event_mask(struct ixgbe_hw *hw, u8 port_num, u16 mask)
+{
+	struct ixgbe_aci_cmd_set_event_mask *cmd;
+	struct ixgbe_aci_desc desc;
+
+	cmd = &desc.params.set_event_mask;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_set_event_mask);
+
+	cmd->lport_num = port_num;
+
+	cmd->event_mask = mask;
+	return ixgbe_aci_send_cmd(hw, &desc, NULL, 0);
+}
+
+/**
+ * ixgbe_configure_lse - enable/disable link status events
+ * @hw: pointer to the HW struct
+ * @activate: true for enable lse, false otherwise
+ * @mask: event mask to be set; a set bit means deactivation of the
+ * corresponding event
+ *
+ * Set the event mask and then enable or disable link status events
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_configure_lse(struct ixgbe_hw *hw, bool activate, u16 mask)
+{
+	int err;
+
+	err = ixgbe_aci_set_event_mask(hw, (u8)hw->bus.func, mask);
+	if (err)
+		return err;
+
+	/* Enabling link status events generation by fw */
+	err = ixgbe_aci_get_link_info(hw, activate, NULL);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+/**
+ * ixgbe_get_media_type_e610 - Gets media type
+ * @hw: pointer to the HW struct
+ *
+ * In order to get the media type, the function gets PHY
+ * capabilities and later on use them to identify the PHY type
+ * checking phy_type_high and phy_type_low.
+ *
+ * Return: the type of media in form of ixgbe_media_type enum
+ * or ixgbe_media_type_unknown in case of an error.
+ */
+enum ixgbe_media_type ixgbe_get_media_type_e610(struct ixgbe_hw *hw)
+{
+	struct ixgbe_aci_cmd_get_phy_caps_data pcaps;
+	int rc;
+
+	rc = ixgbe_update_link_info(hw);
+	if (rc)
+		return ixgbe_media_type_unknown;
+
+	/* If there is no link but PHY (dongle) is available SW should use
+	 * Get PHY Caps admin command instead of Get Link Status, find most
+	 * significant bit that is set in PHY types reported by the command
+	 * and use it to discover media type.
+	 */
+	if (!(hw->link.link_info.link_info & IXGBE_ACI_LINK_UP) &&
+	    (hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE)) {
+		int highest_bit;
+
+		/* Get PHY Capabilities */
+		rc = ixgbe_aci_get_phy_caps(hw, false,
+					    IXGBE_ACI_REPORT_TOPO_CAP_MEDIA,
+					    &pcaps);
+		if (rc)
+			return ixgbe_media_type_unknown;
+
+		highest_bit = fls64(pcaps.phy_type_high);
+		if (highest_bit) {
+			hw->link.link_info.phy_type_high =
+				BIT_ULL(highest_bit - 1);
+			hw->link.link_info.phy_type_low = 0;
+		} else {
+			highest_bit = fls64(pcaps.phy_type_low);
+			if (highest_bit)
+				hw->link.link_info.phy_type_low =
+					BIT_ULL(highest_bit - 1);
+		}
+	}
+
+	/* Based on link status or search above try to discover media type. */
+	hw->phy.media_type = ixgbe_get_media_type_from_phy_type(hw);
+
+	return hw->phy.media_type;
+}
+
+/**
+ * ixgbe_setup_link_e610 - Set up link
+ * @hw: pointer to hardware structure
+ * @speed: new link speed
+ * @autoneg_wait: true when waiting for completion is needed
+ *
+ * Set up the link with the specified speed.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_setup_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed speed,
+			  bool autoneg_wait)
+{
+	/* Simply request FW to perform proper PHY setup */
+	return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait);
+}
+
+/**
+ * ixgbe_check_link_e610 - Determine link and speed status
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @link_up: true when link is up
+ * @link_up_wait_to_complete: bool used to wait for link up or not
+ *
+ * Determine if the link is up and the current link speed
+ * using ACI command (0x0607).
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_check_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
+			  bool *link_up, bool link_up_wait_to_complete)
+{
+	int err;
+	u32 i;
+
+	if (!speed || !link_up)
+		return -EINVAL;
+
+	/* Set get_link_info flag to ensure that fresh
+	 * link information will be obtained from FW
+	 * by sending Get Link Status admin command.
+	 */
+	hw->link.get_link_info = true;
+
+	/* Update link information in adapter context. */
+	err = ixgbe_get_link_status(hw, link_up);
+	if (err)
+		return err;
+
+	/* Wait for link up if it was requested. */
+	if (link_up_wait_to_complete && !(*link_up)) {
+		for (i = 0; i < hw->mac.max_link_up_time; i++) {
+			msleep(100);
+			hw->link.get_link_info = true;
+			err = ixgbe_get_link_status(hw, link_up);
+			if (err)
+				return err;
+			if (*link_up)
+				break;
+		}
+	}
+
+	/* Use link information in adapter context updated by the call
+	 * to ixgbe_get_link_status() to determine current link speed.
+	 * Link speed information is valid only when link up was
+	 * reported by FW.
+	 */
+	if (*link_up) {
+		switch (hw->link.link_info.link_speed) {
+		case IXGBE_ACI_LINK_SPEED_10MB:
+			*speed = IXGBE_LINK_SPEED_10_FULL;
+			break;
+		case IXGBE_ACI_LINK_SPEED_100MB:
+			*speed = IXGBE_LINK_SPEED_100_FULL;
+			break;
+		case IXGBE_ACI_LINK_SPEED_1000MB:
+			*speed = IXGBE_LINK_SPEED_1GB_FULL;
+			break;
+		case IXGBE_ACI_LINK_SPEED_2500MB:
+			*speed = IXGBE_LINK_SPEED_2_5GB_FULL;
+			break;
+		case IXGBE_ACI_LINK_SPEED_5GB:
+			*speed = IXGBE_LINK_SPEED_5GB_FULL;
+			break;
+		case IXGBE_ACI_LINK_SPEED_10GB:
+			*speed = IXGBE_LINK_SPEED_10GB_FULL;
+			break;
+		default:
+			*speed = IXGBE_LINK_SPEED_UNKNOWN;
+			break;
+		}
+	} else {
+		*speed = IXGBE_LINK_SPEED_UNKNOWN;
+	}
+
+	return 0;
+}
+
+/**
+ * ixgbe_get_link_capabilities_e610 - Determine link capabilities
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @autoneg: true when autoneg or autotry is enabled
+ *
+ * Determine speed and AN parameters of a link.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_get_link_capabilities_e610(struct ixgbe_hw *hw,
+				     ixgbe_link_speed *speed,
+				     bool *autoneg)
+{
+	if (!speed || !autoneg)
+		return -EINVAL;
+
+	*autoneg = true;
+	*speed = hw->phy.speeds_supported;
+
+	return 0;
+}
+
+/**
+ * ixgbe_cfg_phy_fc - Configure PHY Flow Control (FC) data based on FC mode
+ * @hw: pointer to hardware structure
+ * @cfg: PHY configuration data to set FC mode
+ * @req_mode: FC mode to configure
+ *
+ * Configures PHY Flow Control according to the provided configuration.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_cfg_phy_fc(struct ixgbe_hw *hw,
+		     struct ixgbe_aci_cmd_set_phy_cfg_data *cfg,
+		     enum ixgbe_fc_mode req_mode)
+{
+	u8 pause_mask = 0x0;
+
+	if (!cfg)
+		return -EINVAL;
+
+	switch (req_mode) {
+	case ixgbe_fc_full:
+		pause_mask |= IXGBE_ACI_PHY_EN_TX_LINK_PAUSE;
+		pause_mask |= IXGBE_ACI_PHY_EN_RX_LINK_PAUSE;
+		break;
+	case ixgbe_fc_rx_pause:
+		pause_mask |= IXGBE_ACI_PHY_EN_RX_LINK_PAUSE;
+		break;
+	case ixgbe_fc_tx_pause:
+		pause_mask |= IXGBE_ACI_PHY_EN_TX_LINK_PAUSE;
+		break;
+	default:
+		break;
+	}
+
+	/* Clear the old pause settings. */
+	cfg->caps &= ~(IXGBE_ACI_PHY_EN_TX_LINK_PAUSE |
+		IXGBE_ACI_PHY_EN_RX_LINK_PAUSE);
+
+	/* Set the new capabilities. */
+	cfg->caps |= pause_mask;
+
+	return 0;
+}
+
+/**
+ * ixgbe_setup_fc_e610 - Set up flow control
+ * @hw: pointer to hardware structure
+ *
+ * Set up flow control. This has to be done during init time.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_setup_fc_e610(struct ixgbe_hw *hw)
+{
+	struct ixgbe_aci_cmd_get_phy_caps_data pcaps = { 0 };
+	struct ixgbe_aci_cmd_set_phy_cfg_data cfg = { 0 };
+	int err;
+
+	/* Get the current PHY config */
+	err = ixgbe_aci_get_phy_caps(hw, false,
+				     IXGBE_ACI_REPORT_ACTIVE_CFG, &pcaps);
+	if (err)
+		return err;
+
+	ixgbe_copy_phy_caps_to_cfg(&pcaps, &cfg);
+
+	/* Configure the set PHY data */
+	err = ixgbe_cfg_phy_fc(hw, &cfg, hw->fc.requested_mode);
+	if (err)
+		return err;
+
+	/* If the capabilities have changed, then set the new config */
+	if (cfg.caps != pcaps.caps) {
+		cfg.caps |= IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT;
+
+		err = ixgbe_aci_set_phy_cfg(hw, &cfg);
+		if (err)
+			return err;
+	}
+
+	return err;
+}
+
+/**
+ * ixgbe_fc_autoneg_e610 - Configure flow control
+ * @hw: pointer to hardware structure
+ *
+ * Configure Flow Control.
+ */
+void ixgbe_fc_autoneg_e610(struct ixgbe_hw *hw)
+{
+	int err;
+
+	/* Get current link err.
+	 * Current FC mode will be stored in the hw context.
+	 */
+	err = ixgbe_aci_get_link_info(hw, false, NULL);
+	if (err)
+		goto no_autoneg;
+
+	/* Check if the link is up */
+	if (!(hw->link.link_info.link_info & IXGBE_ACI_LINK_UP))
+		goto no_autoneg;
+
+	/* Check if auto-negotiation has completed */
+	if (!(hw->link.link_info.an_info & IXGBE_ACI_AN_COMPLETED))
+		goto no_autoneg;
+
+	hw->fc.fc_was_autonegged = true;
+	return;
+
+no_autoneg:
+	hw->fc.fc_was_autonegged = false;
+	hw->fc.current_mode = hw->fc.requested_mode;
+}
+
+/**
+ * ixgbe_disable_rx_e610 - Disable RX unit
+ * @hw: pointer to hardware structure
+ *
+ * Disable RX DMA unit on E610 with use of ACI command (0x000C).
+ *
+ * Return: the exit code of the operation.
+ */
+void ixgbe_disable_rx_e610(struct ixgbe_hw *hw)
+{
+	u32 rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+	u32 pfdtxgswc;
+	int err;
+
+	if (!(rxctrl & IXGBE_RXCTRL_RXEN))
+		return;
+
+	pfdtxgswc = IXGBE_READ_REG(hw, IXGBE_PFDTXGSWC);
+	if (pfdtxgswc & IXGBE_PFDTXGSWC_VT_LBEN) {
+		pfdtxgswc &= ~IXGBE_PFDTXGSWC_VT_LBEN;
+		IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, pfdtxgswc);
+		hw->mac.set_lben = true;
+	} else {
+		hw->mac.set_lben = false;
+	}
+
+	err = ixgbe_aci_disable_rxen(hw);
+
+	/* If we fail - disable RX using register write */
+	if (err) {
+		rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+		if (rxctrl & IXGBE_RXCTRL_RXEN) {
+			rxctrl &= ~IXGBE_RXCTRL_RXEN;
+			IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl);
+		}
+	}
+}
+
+/**
+ * ixgbe_init_phy_ops_e610 - PHY specific init
+ * @hw: pointer to hardware structure
+ *
+ * Initialize any function pointers that were not able to be
+ * set during init_shared_code because the PHY type was not known.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_init_phy_ops_e610(struct ixgbe_hw *hw)
+{
+	struct ixgbe_mac_info *mac = &hw->mac;
+	struct ixgbe_phy_info *phy = &hw->phy;
+	int ret_val;
+
+	if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper)
+		phy->ops.set_phy_power = ixgbe_set_phy_power_e610;
+	else
+		phy->ops.set_phy_power = NULL;
+
+	/* Identify the PHY */
+	ret_val = phy->ops.identify(hw);
+	if (ret_val)
+		return ret_val;
+
+	return ret_val;
+}
+
+/**
+ * ixgbe_identify_phy_e610 - Identify PHY
+ * @hw: pointer to hardware structure
+ *
+ * Determine PHY type, supported speeds and PHY ID.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_identify_phy_e610(struct ixgbe_hw *hw)
+{
+	struct ixgbe_aci_cmd_get_phy_caps_data pcaps;
+	int err;
+
+	/* Set PHY type */
+	hw->phy.type = ixgbe_phy_fw;
+
+	err = ixgbe_aci_get_phy_caps(hw, false,
+				     IXGBE_ACI_REPORT_TOPO_CAP_MEDIA, &pcaps);
+	if (err)
+		return err;
+
+	if (!(pcaps.module_compliance_enforcement &
+	      IXGBE_ACI_MOD_ENFORCE_STRICT_MODE)) {
+		/* Handle lenient mode */
+		err = ixgbe_aci_get_phy_caps(hw, false,
+					     IXGBE_ACI_REPORT_TOPO_CAP_NO_MEDIA,
+					     &pcaps);
+		if (err)
+			return err;
+	}
+
+	/* Determine supported speeds */
+	hw->phy.speeds_supported = IXGBE_LINK_SPEED_UNKNOWN;
+
+	if (pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_10BASE_T ||
+	    pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_10M_SGMII)
+		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_10_FULL;
+	if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_100BASE_TX ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_100M_SGMII ||
+	    pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_100M_USXGMII)
+		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_100_FULL;
+	if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_T  ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_SX ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_LX ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_KX ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1G_SGMII    ||
+	    pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_1G_USXGMII)
+		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_1GB_FULL;
+	if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_T       ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10G_SFI_DA      ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_SR      ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_LR      ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_KR_CR1  ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10G_SFI_AOC_ACC ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10G_SFI_C2C     ||
+	    pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_10G_USXGMII)
+		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_10GB_FULL;
+
+	/* 2.5 and 5 Gbps link speeds must be excluded from the
+	 * auto-negotiation set used during driver initialization due to
+	 * compatibility issues with certain switches. Those issues do not
+	 * exist in case of E610 2.5G SKU device (0x57b1).
+	 */
+	if (!hw->phy.autoneg_advertised &&
+	    hw->device_id != IXGBE_DEV_ID_E610_2_5G_T)
+		hw->phy.autoneg_advertised = hw->phy.speeds_supported;//PK
+
+	if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_2500BASE_T   ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_2500BASE_X   ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_2500BASE_KX  ||
+	    pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_2500M_SGMII ||
+	    pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_2500M_USXGMII)
+		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_2_5GB_FULL;
+
+	if (!hw->phy.autoneg_advertised &&
+	    hw->device_id == IXGBE_DEV_ID_E610_2_5G_T)
+		hw->phy.autoneg_advertised = hw->phy.speeds_supported;//PK
+
+	if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_5GBASE_T  ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_5GBASE_KR ||
+	    pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_5G_USXGMII)
+		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_5GB_FULL;
+
+	/* Set PHY ID */
+	memcpy(&hw->phy.id, pcaps.phy_id_oui, sizeof(u32));
+
+	hw->phy.eee_speeds_supported = IXGBE_LINK_SPEED_10_FULL |
+				       IXGBE_LINK_SPEED_100_FULL |
+				       IXGBE_LINK_SPEED_1GB_FULL;
+	hw->phy.eee_speeds_advertised = hw->phy.eee_speeds_supported;
+
+	return 0;
+}
+
+/**
+ * ixgbe_identify_module_e610 - Identify SFP module type
+ * @hw: pointer to hardware structure
+ *
+ * Identify the SFP module type.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_identify_module_e610(struct ixgbe_hw *hw)
+{
+	bool media_available;
+	u8 module_type;
+	int err;
+
+	err = ixgbe_update_link_info(hw);
+	if (err)
+		return err;
+
+	media_available =
+		(hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE);
+
+	if (media_available) {
+		hw->phy.sfp_type = ixgbe_sfp_type_unknown;
+
+		/* Get module type from hw context updated by
+		 * ixgbe_update_link_info()
+		 */
+		module_type = hw->link.link_info.module_type[IXGBE_ACI_MOD_TYPE_IDENT];
+
+		if ((module_type & IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_PASSIVE) ||
+		    (module_type & IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_ACTIVE)) {
+			hw->phy.sfp_type = ixgbe_sfp_type_da_cu;
+		} else if (module_type & IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_SR) {
+			hw->phy.sfp_type = ixgbe_sfp_type_sr;
+		} else if ((module_type & IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_LR) ||
+			   (module_type & IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_LRM)) {
+			hw->phy.sfp_type = ixgbe_sfp_type_lr;
+		}
+	} else {
+		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+/**
+ * ixgbe_setup_phy_link_e610 - Sets up firmware-controlled PHYs
+ * @hw: pointer to hardware structure
+ *
+ * Set the parameters for the firmware-controlled PHYs.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_setup_phy_link_e610(struct ixgbe_hw *hw)
+{
+	struct ixgbe_aci_cmd_get_phy_caps_data pcaps;
+	struct ixgbe_aci_cmd_set_phy_cfg_data pcfg;
+	u8 rmode = IXGBE_ACI_REPORT_TOPO_CAP_MEDIA;
+	u64 sup_phy_type_low, sup_phy_type_high;
+	int err;
+
+	err = ixgbe_aci_get_link_info(hw, false, NULL);
+	if (err)
+		return err;
+
+	/* If media is not available get default config. */
+	if (!(hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE))
+		rmode = IXGBE_ACI_REPORT_DFLT_CFG;
+
+	err = ixgbe_aci_get_phy_caps(hw, false, rmode, &pcaps);
+	if (err)
+		return err;
+
+	sup_phy_type_low = pcaps.phy_type_low;
+	sup_phy_type_high = pcaps.phy_type_high;
+
+	/* Get Active configuration to avoid unintended changes. */
+	err = ixgbe_aci_get_phy_caps(hw, false, IXGBE_ACI_REPORT_ACTIVE_CFG,
+				     &pcaps);
+	if (err)
+		return err;
+
+	ixgbe_copy_phy_caps_to_cfg(&pcaps, &pcfg);
+
+	/* Set default PHY types for a given speed */
+	pcfg.phy_type_low = 0;
+	pcfg.phy_type_high = 0;
+
+	if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10_FULL) {
+		pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_10BASE_T;
+		pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_10M_SGMII;
+	}
+	if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) {
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_100BASE_TX;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_100M_SGMII;
+		pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_100M_USXGMII;
+	}
+	if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) {
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_T;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_SX;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_LX;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_KX;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1G_SGMII;
+		pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_1G_USXGMII;
+	}
+	if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_2_5GB_FULL) {
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_2500BASE_T;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_2500BASE_X;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_2500BASE_KX;
+		pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_2500M_SGMII;
+		pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_2500M_USXGMII;
+	}
+	if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_5GB_FULL) {
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_5GBASE_T;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_5GBASE_KR;
+		pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_5G_USXGMII;
+	}
+	if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) {
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_T;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10G_SFI_DA;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_SR;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_LR;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_KR_CR1;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10G_SFI_AOC_ACC;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10G_SFI_C2C;
+		pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_10G_USXGMII;
+	}
+
+	/* Mask the set values to avoid requesting unsupported link types */
+	pcfg.phy_type_low &= sup_phy_type_low;
+	pcfg.phy_type_high &= sup_phy_type_high;
+
+	if (pcfg.phy_type_high != pcaps.phy_type_high ||
+	    pcfg.phy_type_low != pcaps.phy_type_low ||
+	    pcfg.caps != pcaps.caps) {
+		pcfg.caps |= IXGBE_ACI_PHY_ENA_LINK;
+		pcfg.caps |= IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT;
+
+		err = ixgbe_aci_set_phy_cfg(hw, &pcfg);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/**
+ * ixgbe_set_phy_power_e610 - Control power for copper PHY
+ * @hw: pointer to hardware structure
+ * @on: true for on, false for off
+ *
+ * Set the power on/off of the PHY
+ * by getting its capabilities and setting the appropriate
+ * configuration parameters.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_set_phy_power_e610(struct ixgbe_hw *hw, bool on)
+{
+	struct ixgbe_aci_cmd_get_phy_caps_data phy_caps = { 0 };
+	struct ixgbe_aci_cmd_set_phy_cfg_data phy_cfg = { 0 };
+	int err;
+
+	err = ixgbe_aci_get_phy_caps(hw, false,
+				     IXGBE_ACI_REPORT_ACTIVE_CFG,
+				     &phy_caps);
+	if (err)
+		return err;
+
+	ixgbe_copy_phy_caps_to_cfg(&phy_caps, &phy_cfg);
+
+	if (on)
+		phy_cfg.caps &= ~IXGBE_ACI_PHY_ENA_LOW_POWER;
+	else
+		phy_cfg.caps |= IXGBE_ACI_PHY_ENA_LOW_POWER;
+
+	/* PHY is already in requested power mode. */
+	if (phy_caps.caps == phy_cfg.caps)
+		return 0;
+
+	phy_cfg.caps |= IXGBE_ACI_PHY_ENA_LINK;
+	phy_cfg.caps |= IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT;
+
+	err = ixgbe_aci_set_phy_cfg(hw, &phy_cfg);
+
+	return err;
+}
+
+/**
+ * ixgbe_enter_lplu_e610 - Transition to low power states
+ * @hw: pointer to hardware structure
+ *
+ * Configures Low Power Link Up on transition to low power states
+ * (from D0 to non-D0). Link is required to enter LPLU so avoid resetting the
+ * X557 PHY immediately prior to entering LPLU.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_enter_lplu_e610(struct ixgbe_hw *hw)
+{
+	struct ixgbe_aci_cmd_get_phy_caps_data phy_caps = { 0 };
+	struct ixgbe_aci_cmd_set_phy_cfg_data phy_cfg = { 0 };
+	int err;
+
+	err = ixgbe_aci_get_phy_caps(hw, false,
+				     IXGBE_ACI_REPORT_ACTIVE_CFG,
+				     &phy_caps);
+	if (err)
+		return err;
+
+	ixgbe_copy_phy_caps_to_cfg(&phy_caps, &phy_cfg);
+
+	phy_cfg.low_power_ctrl_an |= IXGBE_ACI_PHY_EN_D3COLD_LOW_POWER_AUTONEG;
+
+	err = ixgbe_aci_set_phy_cfg(hw, &phy_cfg);
+
+	return err;
+}
+
+/**
+ * ixgbe_aci_get_netlist_node - get a node handle
+ * @hw: pointer to the hw struct
+ * @cmd: get_link_topo AQ structure
+ * @node_part_number: output node part number if node found
+ * @node_handle: output node handle parameter if node found
+ *
+ * Get the netlist node and assigns it to
+ * the provided handle using ACI command (0x06E0).
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_aci_get_netlist_node(struct ixgbe_hw *hw,
+			       struct ixgbe_aci_cmd_get_link_topo *cmd,
+			       u8 *node_part_number, u16 *node_handle)
+{
+	struct ixgbe_aci_desc desc;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_link_topo);
+	desc.params.get_link_topo = *cmd;
+
+	if (ixgbe_aci_send_cmd(hw, &desc, NULL, 0))
+		return -EOPNOTSUPP;
+
+	if (node_handle)
+		*node_handle = desc.params.get_link_topo.addr.handle;
+	if (node_part_number)
+		*node_part_number = desc.params.get_link_topo.node_part_num;
+
+	return 0;
+}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
index 5c5a676..4a4f969 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
@@ -27,5 +27,37 @@ int ixgbe_aci_get_phy_caps(struct ixgbe_hw *hw, bool qual_mods, u8 report_mode,
 			   struct ixgbe_aci_cmd_get_phy_caps_data *pcaps);
 void ixgbe_copy_phy_caps_to_cfg(struct ixgbe_aci_cmd_get_phy_caps_data *caps,
 				struct ixgbe_aci_cmd_set_phy_cfg_data *cfg);
+int ixgbe_aci_set_phy_cfg(struct ixgbe_hw *hw,
+			  struct ixgbe_aci_cmd_set_phy_cfg_data *cfg);
+int ixgbe_aci_set_link_restart_an(struct ixgbe_hw *hw, bool ena_link);
+int ixgbe_update_link_info(struct ixgbe_hw *hw);
+int ixgbe_get_link_status(struct ixgbe_hw *hw, bool *link_up);
+int ixgbe_aci_get_link_info(struct ixgbe_hw *hw, bool ena_lse,
+			    struct ixgbe_link_status *link);
+int ixgbe_aci_set_event_mask(struct ixgbe_hw *hw, u8 port_num, u16 mask);
+int ixgbe_configure_lse(struct ixgbe_hw *hw, bool activate, u16 mask);
+enum ixgbe_media_type ixgbe_get_media_type_e610(struct ixgbe_hw *hw);
+int ixgbe_setup_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed speed,
+			  bool autoneg_wait);
+int ixgbe_check_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
+			  bool *link_up, bool link_up_wait_to_complete);
+int ixgbe_get_link_capabilities_e610(struct ixgbe_hw *hw,
+				     ixgbe_link_speed *speed,
+				     bool *autoneg);
+int ixgbe_cfg_phy_fc(struct ixgbe_hw *hw,
+		     struct ixgbe_aci_cmd_set_phy_cfg_data *cfg,
+		     enum ixgbe_fc_mode req_mode);
+int ixgbe_setup_fc_e610(struct ixgbe_hw *hw);
+void ixgbe_fc_autoneg_e610(struct ixgbe_hw *hw);
+void ixgbe_disable_rx_e610(struct ixgbe_hw *hw);
+int ixgbe_init_phy_ops_e610(struct ixgbe_hw *hw);
+int ixgbe_identify_phy_e610(struct ixgbe_hw *hw);
+int ixgbe_identify_module_e610(struct ixgbe_hw *hw);
+int ixgbe_setup_phy_link_e610(struct ixgbe_hw *hw);
+int ixgbe_set_phy_power_e610(struct ixgbe_hw *hw, bool on);
+int ixgbe_enter_lplu_e610(struct ixgbe_hw *hw);
+int ixgbe_aci_get_netlist_node(struct ixgbe_hw *hw,
+			       struct ixgbe_aci_cmd_get_link_topo *cmd,
+			       u8 *node_part_number, u16 *node_handle);
 
 #endif /* _IXGBE_E610_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
index 6c6d990..1f97652 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
@@ -652,6 +652,7 @@ struct ixgbe_aci_cmd_link_topo_params {
 #define IXGBE_ACI_LINK_TOPO_NODE_TYPE_CLK_MUX	10
 #define IXGBE_ACI_LINK_TOPO_NODE_TYPE_GPS	11
 #define IXGBE_ACI_LINK_TOPO_NODE_CTX_S		4
+#define IXGBE_ACI_LINK_TOPO_NODE_CTX_M		GENMASK(7, 4)
 #define IXGBE_ACI_LINK_TOPO_NODE_CTX_GLOBAL			0
 #define IXGBE_ACI_LINK_TOPO_NODE_CTX_BOARD			1
 #define IXGBE_ACI_LINK_TOPO_NODE_CTX_PORT			2
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH iwl-next v9 4/7] ixgbe: Add support for NVM handling in E610 device
  2024-10-03 14:16 [PATCH iwl-next v9 0/7] ixgbe: Add support for Intel(R) E610 device Piotr Kwapulinski
                   ` (2 preceding siblings ...)
  2024-10-03 14:16 ` [PATCH iwl-next v9 3/7] ixgbe: Add link management support for E610 device Piotr Kwapulinski
@ 2024-10-03 14:16 ` Piotr Kwapulinski
  2024-10-03 14:16 ` [PATCH iwl-next v9 5/7] ixgbe: Add ixgbe_x540 multiple header inclusion protection Piotr Kwapulinski
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 16+ messages in thread
From: Piotr Kwapulinski @ 2024-10-03 14:16 UTC (permalink / raw)
  To: intel-wired-lan
  Cc: netdev, Piotr Kwapulinski, Stefan Wegrzyn, Jedrzej Jagielski,
	Michal Swiatkowski, Simon Horman

Add low level support for accessing NVM in E610 device. NVM operations are
handled via the Admin Command Interface. Add the following NVM specific
operations:
- acquire, release, read
- validate checksum
- read shadow ram

Co-developed-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
Signed-off-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
Co-developed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Signed-off-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Reviewed-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 290 ++++++++++++++++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h |  12 +
 2 files changed, 302 insertions(+)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
index c0c740f..4b76cf1 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
@@ -2124,3 +2124,293 @@ int ixgbe_aci_get_netlist_node(struct ixgbe_hw *hw,
 
 	return 0;
 }
+
+/**
+ * ixgbe_acquire_nvm - Generic request for acquiring the NVM ownership
+ * @hw: pointer to the HW structure
+ * @access: NVM access type (read or write)
+ *
+ * Request NVM ownership.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_acquire_nvm(struct ixgbe_hw *hw,
+		      enum ixgbe_aci_res_access_type access)
+{
+	u32 fla;
+
+	/* Skip if we are in blank NVM programming mode */
+	fla = IXGBE_READ_REG(hw, IXGBE_GLNVM_FLA);
+	if ((fla & IXGBE_GLNVM_FLA_LOCKED_M) == 0)
+		return 0;
+
+	return ixgbe_acquire_res(hw, IXGBE_NVM_RES_ID, access,
+				 IXGBE_NVM_TIMEOUT);
+}
+
+/**
+ * ixgbe_release_nvm - Generic request for releasing the NVM ownership
+ * @hw: pointer to the HW structure
+ *
+ * Release NVM ownership.
+ */
+void ixgbe_release_nvm(struct ixgbe_hw *hw)
+{
+	u32 fla;
+
+	/* Skip if we are in blank NVM programming mode */
+	fla = IXGBE_READ_REG(hw, IXGBE_GLNVM_FLA);
+	if ((fla & IXGBE_GLNVM_FLA_LOCKED_M) == 0)
+		return;
+
+	ixgbe_release_res(hw, IXGBE_NVM_RES_ID);
+}
+
+/**
+ * ixgbe_aci_read_nvm - read NVM
+ * @hw: pointer to the HW struct
+ * @module_typeid: module pointer location in words from the NVM beginning
+ * @offset: byte offset from the module beginning
+ * @length: length of the section to be read (in bytes from the offset)
+ * @data: command buffer (size [bytes] = length)
+ * @last_command: tells if this is the last command in a series
+ * @read_shadow_ram: tell if this is a shadow RAM read
+ *
+ * Read the NVM using ACI command (0x0701).
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_aci_read_nvm(struct ixgbe_hw *hw, u16 module_typeid, u32 offset,
+		       u16 length, void *data, bool last_command,
+		       bool read_shadow_ram)
+{
+	struct ixgbe_aci_cmd_nvm *cmd;
+	struct ixgbe_aci_desc desc;
+
+	if (offset > IXGBE_ACI_NVM_MAX_OFFSET)
+		return -EINVAL;
+
+	cmd = &desc.params.nvm;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_nvm_read);
+
+	if (!read_shadow_ram && module_typeid == IXGBE_ACI_NVM_START_POINT)
+		cmd->cmd_flags |= IXGBE_ACI_NVM_FLASH_ONLY;
+
+	/* If this is the last command in a series, set the proper flag. */
+	if (last_command)
+		cmd->cmd_flags |= IXGBE_ACI_NVM_LAST_CMD;
+	cmd->module_typeid = module_typeid;
+	cmd->offset_low = offset & 0xFFFF;
+	cmd->offset_high = (offset >> 16) & 0xFF;
+	cmd->length = length;
+
+	return ixgbe_aci_send_cmd(hw, &desc, data, length);
+}
+
+/**
+ * ixgbe_nvm_validate_checksum - validate checksum
+ * @hw: pointer to the HW struct
+ *
+ * Verify NVM PFA checksum validity using ACI command (0x0706).
+ * If the checksum verification failed, IXGBE_ERR_NVM_CHECKSUM is returned.
+ * The function acquires and then releases the NVM ownership.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_nvm_validate_checksum(struct ixgbe_hw *hw)
+{
+	struct ixgbe_aci_cmd_nvm_checksum *cmd;
+	struct ixgbe_aci_desc desc;
+	int err;
+
+	err = ixgbe_acquire_nvm(hw, IXGBE_RES_READ);
+	if (err)
+		return err;
+
+	cmd = &desc.params.nvm_checksum;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_nvm_checksum);
+	cmd->flags = IXGBE_ACI_NVM_CHECKSUM_VERIFY;
+
+	err = ixgbe_aci_send_cmd(hw, &desc, NULL, 0);
+
+	ixgbe_release_nvm(hw);
+
+	if (!err && cmd->checksum != IXGBE_ACI_NVM_CHECKSUM_CORRECT) {
+		struct ixgbe_adapter *adapter = container_of(hw, struct ixgbe_adapter,
+							     hw);
+
+		err = -EIO;
+		netdev_err(adapter->netdev, "Invalid Shadow Ram checksum");
+	}
+
+	return err;
+}
+
+/**
+ * ixgbe_read_sr_word_aci - Reads Shadow RAM via ACI
+ * @hw: pointer to the HW structure
+ * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
+ * @data: word read from the Shadow RAM
+ *
+ * Reads one 16 bit word from the Shadow RAM using ixgbe_read_flat_nvm.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_read_sr_word_aci(struct ixgbe_hw  *hw, u16 offset, u16 *data)
+{
+	u32 bytes = sizeof(u16);
+	u16 data_local;
+	int err;
+
+	err = ixgbe_read_flat_nvm(hw, offset * sizeof(u16), &bytes,
+				  (u8 *)&data_local, true);
+	if (err)
+		return err;
+
+	*data = data_local;
+	return 0;
+}
+
+/**
+ * ixgbe_read_flat_nvm - Read portion of NVM by flat offset
+ * @hw: pointer to the HW struct
+ * @offset: offset from beginning of NVM
+ * @length: (in) number of bytes to read; (out) number of bytes actually read
+ * @data: buffer to return data in (sized to fit the specified length)
+ * @read_shadow_ram: if true, read from shadow RAM instead of NVM
+ *
+ * Reads a portion of the NVM, as a flat memory space. This function correctly
+ * breaks read requests across Shadow RAM sectors, prevents Shadow RAM size
+ * from being exceeded in case of Shadow RAM read requests and ensures that no
+ * single read request exceeds the maximum 4KB read for a single admin command.
+ *
+ * Returns an error code on failure. Note that the data pointer may be
+ * partially updated if some reads succeed before a failure.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_read_flat_nvm(struct ixgbe_hw  *hw, u32 offset, u32 *length,
+			u8 *data, bool read_shadow_ram)
+{
+	u32 inlen = *length;
+	u32 bytes_read = 0;
+	bool last_cmd;
+	int err;
+
+	/* Verify the length of the read if this is for the Shadow RAM */
+	if (read_shadow_ram && ((offset + inlen) >
+				(hw->eeprom.word_size * 2u)))
+		return -EINVAL;
+
+	do {
+		u32 read_size, sector_offset;
+
+		/* ixgbe_aci_read_nvm cannot read more than 4KB at a time.
+		 * Additionally, a read from the Shadow RAM may not cross over
+		 * a sector boundary. Conveniently, the sector size is also 4KB.
+		 */
+		sector_offset = offset % IXGBE_ACI_MAX_BUFFER_SIZE;
+		read_size = min_t(u32,
+				  IXGBE_ACI_MAX_BUFFER_SIZE - sector_offset,
+				  inlen - bytes_read);
+
+		last_cmd = !(bytes_read + read_size < inlen);
+
+		/* ixgbe_aci_read_nvm takes the length as a u16. Our read_size
+		 * is calculated using a u32, but the IXGBE_ACI_MAX_BUFFER_SIZE
+		 * maximum size guarantees that it will fit within the 2 bytes.
+		 */
+		err = ixgbe_aci_read_nvm(hw, IXGBE_ACI_NVM_START_POINT,
+					 offset, (u16)read_size,
+					 data + bytes_read, last_cmd,
+					 read_shadow_ram);
+		if (err)
+			break;
+
+		bytes_read += read_size;
+		offset += read_size;
+	} while (!last_cmd);
+
+	*length = bytes_read;
+	return err;
+}
+
+/**
+ * ixgbe_read_ee_aci_e610 - Read EEPROM word using the admin command.
+ * @hw: pointer to hardware structure
+ * @offset: offset of  word in the EEPROM to read
+ * @data: word read from the EEPROM
+ *
+ * Reads a 16 bit word from the EEPROM using the ACI.
+ * If the EEPROM params are not initialized, the function
+ * initialize them before proceeding with reading.
+ * The function acquires and then releases the NVM ownership.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_read_ee_aci_e610(struct ixgbe_hw *hw, u16 offset, u16 *data)
+{
+	int err;
+
+	if (hw->eeprom.type == ixgbe_eeprom_uninitialized) {
+		err = hw->eeprom.ops.init_params(hw);
+		if (err)
+			return err;
+	}
+
+	err = ixgbe_acquire_nvm(hw, IXGBE_RES_READ);
+	if (err)
+		return err;
+
+	err = ixgbe_read_sr_word_aci(hw, offset, data);
+	ixgbe_release_nvm(hw);
+
+	return err;
+}
+
+/**
+ * ixgbe_validate_eeprom_checksum_e610 - Validate EEPROM checksum
+ * @hw: pointer to hardware structure
+ * @checksum_val: calculated checksum
+ *
+ * Performs checksum calculation and validates the EEPROM checksum. If the
+ * caller does not need checksum_val, the value can be NULL.
+ * If the EEPROM params are not initialized, the function
+ * initialize them before proceeding.
+ * The function acquires and then releases the NVM ownership.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_validate_eeprom_checksum_e610(struct ixgbe_hw *hw, u16 *checksum_val)
+{
+	int err;
+
+	if (hw->eeprom.type == ixgbe_eeprom_uninitialized) {
+		err = hw->eeprom.ops.init_params(hw);
+		if (err)
+			return err;
+	}
+
+	err = ixgbe_nvm_validate_checksum(hw);
+	if (err)
+		return err;
+
+	if (checksum_val) {
+		u16 tmp_checksum;
+
+		err = ixgbe_acquire_nvm(hw, IXGBE_RES_READ);
+		if (err)
+			return err;
+
+		err = ixgbe_read_sr_word_aci(hw, E610_SR_SW_CHECKSUM_WORD,
+					     &tmp_checksum);
+		ixgbe_release_nvm(hw);
+
+		if (!err)
+			*checksum_val = tmp_checksum;
+	}
+
+	return err;
+}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
index 4a4f969..412ddd1 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
@@ -59,5 +59,17 @@ int ixgbe_enter_lplu_e610(struct ixgbe_hw *hw);
 int ixgbe_aci_get_netlist_node(struct ixgbe_hw *hw,
 			       struct ixgbe_aci_cmd_get_link_topo *cmd,
 			       u8 *node_part_number, u16 *node_handle);
+int ixgbe_acquire_nvm(struct ixgbe_hw *hw,
+		      enum ixgbe_aci_res_access_type access);
+void ixgbe_release_nvm(struct ixgbe_hw *hw);
+int ixgbe_aci_read_nvm(struct ixgbe_hw *hw, u16 module_typeid, u32 offset,
+		       u16 length, void *data, bool last_command,
+		       bool read_shadow_ram);
+int ixgbe_nvm_validate_checksum(struct ixgbe_hw *hw);
+int ixgbe_read_sr_word_aci(struct ixgbe_hw  *hw, u16 offset, u16 *data);
+int ixgbe_read_flat_nvm(struct ixgbe_hw  *hw, u32 offset, u32 *length,
+			u8 *data, bool read_shadow_ram);
+int ixgbe_read_ee_aci_e610(struct ixgbe_hw *hw, u16 offset, u16 *data);
+int ixgbe_validate_eeprom_checksum_e610(struct ixgbe_hw *hw, u16 *checksum_val);
 
 #endif /* _IXGBE_E610_H_ */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH iwl-next v9 5/7] ixgbe: Add ixgbe_x540 multiple header inclusion protection
  2024-10-03 14:16 [PATCH iwl-next v9 0/7] ixgbe: Add support for Intel(R) E610 device Piotr Kwapulinski
                   ` (3 preceding siblings ...)
  2024-10-03 14:16 ` [PATCH iwl-next v9 4/7] ixgbe: Add support for NVM handling in " Piotr Kwapulinski
@ 2024-10-03 14:16 ` Piotr Kwapulinski
  2024-10-17  9:47   ` Simon Horman
  2024-10-03 14:16 ` [PATCH iwl-next v9 6/7] ixgbe: Clean up the E610 link management related code Piotr Kwapulinski
  2024-10-03 14:16 ` [PATCH iwl-next v9 7/7] ixgbe: Enable link management in E610 device Piotr Kwapulinski
  6 siblings, 1 reply; 16+ messages in thread
From: Piotr Kwapulinski @ 2024-10-03 14:16 UTC (permalink / raw)
  To: intel-wired-lan; +Cc: netdev, Piotr Kwapulinski

Required to adopt x540 specific functions by E610 device.

Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_x540.h | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.h
index b69a680..6ed360c 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.h
@@ -1,5 +1,8 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright(c) 1999 - 2018 Intel Corporation. */
+/* Copyright(c) 1999 - 2024 Intel Corporation. */
+
+#ifndef _IXGBE_X540_H_
+#define _IXGBE_X540_H_
 
 #include "ixgbe_type.h"
 
@@ -17,3 +20,5 @@ int ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask);
 void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask);
 void ixgbe_init_swfw_sync_X540(struct ixgbe_hw *hw);
 int ixgbe_init_eeprom_params_X540(struct ixgbe_hw *hw);
+
+#endif /* _IXGBE_X540_H_ */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH iwl-next v9 6/7] ixgbe: Clean up the E610 link management related code
  2024-10-03 14:16 [PATCH iwl-next v9 0/7] ixgbe: Add support for Intel(R) E610 device Piotr Kwapulinski
                   ` (4 preceding siblings ...)
  2024-10-03 14:16 ` [PATCH iwl-next v9 5/7] ixgbe: Add ixgbe_x540 multiple header inclusion protection Piotr Kwapulinski
@ 2024-10-03 14:16 ` Piotr Kwapulinski
  2024-10-03 14:16 ` [PATCH iwl-next v9 7/7] ixgbe: Enable link management in E610 device Piotr Kwapulinski
  6 siblings, 0 replies; 16+ messages in thread
From: Piotr Kwapulinski @ 2024-10-03 14:16 UTC (permalink / raw)
  To: intel-wired-lan; +Cc: netdev, Piotr Kwapulinski, Simon Horman

Required for enabling the link management in E610 device.

Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 17 +++++++++++------
 drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 12 ++++++------
 2 files changed, 17 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 0302a21..6bf5adcb 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -236,6 +236,9 @@ static int ixgbe_get_parent_bus_info(struct ixgbe_adapter *adapter)
  * bandwidth details should be gathered from the parent bus instead of from the
  * device. Used to ensure that various locations all have the correct device ID
  * checks.
+ *
+ * Return: true if information should be collected from the parent bus, false
+ *         otherwise
  */
 static inline bool ixgbe_pcie_from_parent(struct ixgbe_hw *hw)
 {
@@ -5532,7 +5535,9 @@ static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter)
  * ixgbe_non_sfp_link_config - set up non-SFP+ link
  * @hw: pointer to private hardware struct
  *
- * Returns 0 on success, negative on failure
+ * Configure non-SFP link.
+ *
+ * Return: 0 on success, negative on failure
  **/
 static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw)
 {
@@ -7221,11 +7226,11 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
 	for (i = 0; i < 16; i++) {
 		hwstats->qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i));
 		hwstats->qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i));
-		if ((hw->mac.type == ixgbe_mac_82599EB) ||
-		    (hw->mac.type == ixgbe_mac_X540) ||
-		    (hw->mac.type == ixgbe_mac_X550) ||
-		    (hw->mac.type == ixgbe_mac_X550EM_x) ||
-		    (hw->mac.type == ixgbe_mac_x550em_a)) {
+		if (hw->mac.type == ixgbe_mac_82599EB ||
+		    hw->mac.type == ixgbe_mac_X540 ||
+		    hw->mac.type == ixgbe_mac_X550 ||
+		    hw->mac.type == ixgbe_mac_X550EM_x ||
+		    hw->mac.type == ixgbe_mac_x550em_a) {
 			hwstats->qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC_L(i));
 			IXGBE_READ_REG(hw, IXGBE_QBTC_H(i)); /* to clear */
 			hwstats->qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC_L(i));
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
index a5f6449..7eeafc9 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
@@ -3504,13 +3504,13 @@ static int ixgbe_reset_hw_X550em(struct ixgbe_hw *hw)
 	return status;
 }
 
-/** ixgbe_set_ethertype_anti_spoofing_X550 - Enable/Disable Ethertype
+/** ixgbe_set_ethertype_anti_spoofing_x550 - Enable/Disable Ethertype
  *	anti-spoofing
  *  @hw:  pointer to hardware structure
  *  @enable: enable or disable switch for Ethertype anti-spoofing
  *  @vf: Virtual Function pool - VF Pool to set for Ethertype anti-spoofing
  **/
-static void ixgbe_set_ethertype_anti_spoofing_X550(struct ixgbe_hw *hw,
+static void ixgbe_set_ethertype_anti_spoofing_x550(struct ixgbe_hw *hw,
 						   bool enable, int vf)
 {
 	int vf_target_reg = vf >> 3;
@@ -3526,12 +3526,12 @@ static void ixgbe_set_ethertype_anti_spoofing_X550(struct ixgbe_hw *hw,
 	IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), pfvfspoof);
 }
 
-/** ixgbe_set_source_address_pruning_X550 - Enable/Disbale src address pruning
+/** ixgbe_set_source_address_pruning_x550 - Enable/Disable src address pruning
  *  @hw: pointer to hardware structure
  *  @enable: enable or disable source address pruning
  *  @pool: Rx pool to set source address pruning for
  **/
-static void ixgbe_set_source_address_pruning_X550(struct ixgbe_hw *hw,
+static void ixgbe_set_source_address_pruning_x550(struct ixgbe_hw *hw,
 						  bool enable,
 						  unsigned int pool)
 {
@@ -3830,9 +3830,9 @@ static int ixgbe_write_phy_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr,
 	.set_mac_anti_spoofing		= &ixgbe_set_mac_anti_spoofing, \
 	.set_vlan_anti_spoofing		= &ixgbe_set_vlan_anti_spoofing, \
 	.set_source_address_pruning	= \
-				&ixgbe_set_source_address_pruning_X550, \
+				&ixgbe_set_source_address_pruning_x550, \
 	.set_ethertype_anti_spoofing	= \
-				&ixgbe_set_ethertype_anti_spoofing_X550, \
+				&ixgbe_set_ethertype_anti_spoofing_x550, \
 	.disable_rx_buff		= &ixgbe_disable_rx_buff_generic, \
 	.enable_rx_buff			= &ixgbe_enable_rx_buff_generic, \
 	.get_thermal_sensor_data	= NULL, \
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH iwl-next v9 7/7] ixgbe: Enable link management in E610 device
  2024-10-03 14:16 [PATCH iwl-next v9 0/7] ixgbe: Add support for Intel(R) E610 device Piotr Kwapulinski
                   ` (5 preceding siblings ...)
  2024-10-03 14:16 ` [PATCH iwl-next v9 6/7] ixgbe: Clean up the E610 link management related code Piotr Kwapulinski
@ 2024-10-03 14:16 ` Piotr Kwapulinski
  6 siblings, 0 replies; 16+ messages in thread
From: Piotr Kwapulinski @ 2024-10-03 14:16 UTC (permalink / raw)
  To: intel-wired-lan
  Cc: netdev, Piotr Kwapulinski, Carolyn Wyborny, Jedrzej Jagielski,
	Jan Glaza, Simon Horman

Add high level link management support for E610 device. Enable the
following features:
- driver load
- bring up network interface
- IP address assignment
- pass traffic
- show statistics (e.g. via ethtool)
- disable network interface
- driver unload

Co-developed-by: Carolyn Wyborny <carolyn.wyborny@intel.com>
Signed-off-by: Carolyn Wyborny <carolyn.wyborny@intel.com>
Co-developed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Signed-off-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Reviewed-by: Jan Glaza <jan.glaza@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe.h      |  14 +-
 .../net/ethernet/intel/ixgbe/ixgbe_82599.c    |   3 +-
 .../net/ethernet/intel/ixgbe/ixgbe_common.c   |  19 +-
 .../net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c   |   3 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 163 +++++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h |   1 +
 .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c  |   6 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c  |   3 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 414 +++++++++++++++++-
 drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c  |   4 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c  |   5 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c |  12 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c |  21 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_x550.h |  20 +
 14 files changed, 657 insertions(+), 31 deletions(-)
 create mode 100644 drivers/net/ethernet/intel/ixgbe/ixgbe_x550.h

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 559b443..3b2bba6e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright(c) 1999 - 2018 Intel Corporation. */
+/* Copyright(c) 1999 - 2024 Intel Corporation. */
 
 #ifndef _IXGBE_H_
 #define _IXGBE_H_
@@ -20,6 +20,7 @@
 #include "ixgbe_type.h"
 #include "ixgbe_common.h"
 #include "ixgbe_dcb.h"
+#include "ixgbe_e610.h"
 #if IS_ENABLED(CONFIG_FCOE)
 #define IXGBE_FCOE
 #include "ixgbe_fcoe.h"
@@ -173,6 +174,7 @@ enum ixgbe_tx_flags {
 #define VMDQ_P(p)   ((p) + adapter->ring_feature[RING_F_VMDQ].offset)
 #define IXGBE_82599_VF_DEVICE_ID        0x10ED
 #define IXGBE_X540_VF_DEVICE_ID         0x1515
+#define IXGBE_E610_VF_DEVICE_ID		0x57AD
 
 #define UPDATE_VF_COUNTER_32bit(reg, last_counter, counter)	\
 	{							\
@@ -654,6 +656,7 @@ struct ixgbe_adapter {
 #define IXGBE_FLAG2_RSS_FIELD_IPV6_UDP		BIT(9)
 #define IXGBE_FLAG2_PTP_PPS_ENABLED		BIT(10)
 #define IXGBE_FLAG2_PHY_INTERRUPT		BIT(11)
+#define IXGBE_FLAG2_FW_ASYNC_EVENT		BIT(12)
 #define IXGBE_FLAG2_VLAN_PROMISC		BIT(13)
 #define IXGBE_FLAG2_EEE_CAPABLE			BIT(14)
 #define IXGBE_FLAG2_EEE_ENABLED			BIT(15)
@@ -661,7 +664,9 @@ struct ixgbe_adapter {
 #define IXGBE_FLAG2_IPSEC_ENABLED		BIT(17)
 #define IXGBE_FLAG2_VF_IPSEC_ENABLED		BIT(18)
 #define IXGBE_FLAG2_AUTO_DISABLE_VF		BIT(19)
-
+#define IXGBE_FLAG2_PHY_FW_LOAD_FAILED		BIT(20)
+#define IXGBE_FLAG2_NO_MEDIA			BIT(21)
+#define IXGBE_FLAG2_MOD_POWER_UNSUPPORTED	BIT(22)
 	/* Tx fast path data */
 	int num_tx_queues;
 	u16 tx_itr_setting;
@@ -793,6 +798,7 @@ struct ixgbe_adapter {
 	u32 vferr_refcount;
 	struct ixgbe_mac_addr *mac_table;
 	struct kobject *info_kobj;
+	u16 lse_mask;
 #ifdef CONFIG_IXGBE_HWMON
 	struct hwmon_buff *ixgbe_hwmon_buff;
 #endif /* CONFIG_IXGBE_HWMON */
@@ -849,6 +855,7 @@ static inline u8 ixgbe_max_rss_indices(struct ixgbe_adapter *adapter)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		return IXGBE_MAX_RSS_INDICES_X550;
 	default:
 		return 0;
@@ -874,6 +881,7 @@ enum ixgbe_state_t {
 	__IXGBE_PTP_RUNNING,
 	__IXGBE_PTP_TX_IN_PROGRESS,
 	__IXGBE_RESET_REQUESTED,
+	__IXGBE_PHY_INIT_COMPLETE,
 };
 
 struct ixgbe_cb {
@@ -896,6 +904,7 @@ enum ixgbe_boards {
 	board_x550em_x_fw,
 	board_x550em_a,
 	board_x550em_a_fw,
+	board_e610,
 };
 
 extern const struct ixgbe_info ixgbe_82598_info;
@@ -906,6 +915,7 @@ extern const struct ixgbe_info ixgbe_X550EM_x_info;
 extern const struct ixgbe_info ixgbe_x550em_x_fw_info;
 extern const struct ixgbe_info ixgbe_x550em_a_info;
 extern const struct ixgbe_info ixgbe_x550em_a_fw_info;
+extern const struct ixgbe_info ixgbe_e610_info;
 #ifdef CONFIG_IXGBE_DCB
 extern const struct dcbnl_rtnl_ops ixgbe_dcbnl_ops;
 #endif
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
index cdaf087..964988b 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Copyright(c) 1999 - 2018 Intel Corporation. */
+/* Copyright(c) 1999 - 2024 Intel Corporation. */
 
 #include <linux/pci.h>
 #include <linux/delay.h>
@@ -1615,6 +1615,7 @@ int ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw,
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		IXGBE_WRITE_REG(hw, IXGBE_FDIRSCTPM, ~fdirtcpm);
 		break;
 	default:
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
index bfab2c0..7beaf6e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Copyright(c) 1999 - 2018 Intel Corporation. */
+/* Copyright(c) 1999 - 2024 Intel Corporation. */
 
 #include <linux/pci.h>
 #include <linux/delay.h>
@@ -58,6 +58,7 @@ bool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw)
 		switch (hw->device_id) {
 		case IXGBE_DEV_ID_X550EM_A_SFP:
 		case IXGBE_DEV_ID_X550EM_A_SFP_N:
+		case IXGBE_DEV_ID_E610_SFP:
 			supported = false;
 			break;
 		default:
@@ -88,6 +89,8 @@ bool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw)
 		case IXGBE_DEV_ID_X550EM_A_10G_T:
 		case IXGBE_DEV_ID_X550EM_A_1G_T:
 		case IXGBE_DEV_ID_X550EM_A_1G_T_L:
+		case IXGBE_DEV_ID_E610_10G_T:
+		case IXGBE_DEV_ID_E610_2_5G_T:
 			supported = true;
 			break;
 		default:
@@ -469,9 +472,14 @@ int ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw)
 		}
 	}
 
-	if (hw->mac.type == ixgbe_mac_X550 || hw->mac.type == ixgbe_mac_X540) {
+	if (hw->mac.type == ixgbe_mac_X550 ||
+	    hw->mac.type == ixgbe_mac_X540 ||
+	    hw->mac.type == ixgbe_mac_e610) {
 		if (hw->phy.id == 0)
 			hw->phy.ops.identify(hw);
+	}
+
+	if (hw->mac.type == ixgbe_mac_X550 || hw->mac.type == ixgbe_mac_X540) {
 		hw->phy.ops.read_reg(hw, IXGBE_PCRC8ECL, MDIO_MMD_PCS, &i);
 		hw->phy.ops.read_reg(hw, IXGBE_PCRC8ECH, MDIO_MMD_PCS, &i);
 		hw->phy.ops.read_reg(hw, IXGBE_LDPCECL, MDIO_MMD_PCS, &i);
@@ -2922,6 +2930,10 @@ u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw)
 		pcie_offset = IXGBE_PCIE_MSIX_82599_CAPS;
 		max_msix_count = IXGBE_MAX_MSIX_VECTORS_82599;
 		break;
+	case ixgbe_mac_e610:
+		pcie_offset = IXGBE_PCIE_MSIX_E610_CAPS;
+		max_msix_count = IXGBE_MAX_MSIX_VECTORS_82599;
+		break;
 	default:
 		return 1;
 	}
@@ -3370,7 +3382,8 @@ int ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
 		*speed = IXGBE_LINK_SPEED_1GB_FULL;
 		break;
 	case IXGBE_LINKS_SPEED_100_82599:
-		if ((hw->mac.type >= ixgbe_mac_X550) &&
+		if ((hw->mac.type >= ixgbe_mac_X550 ||
+		     hw->mac.type == ixgbe_mac_e610) &&
 		    (links_reg & IXGBE_LINKS_SPEED_NON_STD))
 			*speed = IXGBE_LINK_SPEED_5GB_FULL;
 		else
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
index f2709b1..19d6b6f 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Copyright(c) 1999 - 2018 Intel Corporation. */
+/* Copyright(c) 1999 - 2024 Intel Corporation. */
 
 #include "ixgbe.h"
 #include <linux/dcbnl.h>
@@ -154,6 +154,7 @@ static void ixgbe_dcbnl_get_perm_hw_addr(struct net_device *netdev,
 	case ixgbe_mac_82599EB:
 	case ixgbe_mac_X540:
 	case ixgbe_mac_X550:
+	case ixgbe_mac_e610:
 		for (j = 0; j < netdev->addr_len; j++, i++)
 			perm_addr[i] = adapter->hw.mac.san_addr[j];
 		break;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
index 4b76cf1..2f0351d 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
@@ -3,6 +3,7 @@
 
 #include "ixgbe_common.h"
 #include "ixgbe_e610.h"
+#include "ixgbe_x550.h"
 #include "ixgbe_type.h"
 #include "ixgbe_x540.h"
 #include "ixgbe_phy.h"
@@ -2414,3 +2415,165 @@ int ixgbe_validate_eeprom_checksum_e610(struct ixgbe_hw *hw, u16 *checksum_val)
 
 	return err;
 }
+
+/**
+ * ixgbe_reset_hw_e610 - Perform hardware reset
+ * @hw: pointer to hardware structure
+ *
+ * Resets the hardware by resetting the transmit and receive units, masks
+ * and clears all interrupts, and performs a reset.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_reset_hw_e610(struct ixgbe_hw *hw)
+{
+	u32 swfw_mask = hw->phy.phy_semaphore_mask;
+	u32 ctrl, i;
+	int err;
+
+	/* Call adapter stop to disable tx/rx and clear interrupts */
+	err = hw->mac.ops.stop_adapter(hw);
+	if (err)
+		goto reset_hw_out;
+
+	/* Flush pending Tx transactions. */
+	ixgbe_clear_tx_pending(hw);
+
+	hw->phy.ops.init(hw);
+mac_reset_top:
+	err = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask);
+	if (err)
+		return -EBUSY;
+	ctrl = IXGBE_CTRL_RST;
+	ctrl |= IXGBE_READ_REG(hw, IXGBE_CTRL);
+	IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl);
+	IXGBE_WRITE_FLUSH(hw);
+	hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+
+	/* Poll for reset bit to self-clear indicating reset is complete */
+	for (i = 0; i < 10; i++) {
+		udelay(1);
+		ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
+		if (!(ctrl & IXGBE_CTRL_RST_MASK))
+			break;
+	}
+
+	if (ctrl & IXGBE_CTRL_RST_MASK) {
+		struct ixgbe_adapter *adapter = container_of(hw, struct ixgbe_adapter,
+							     hw);
+
+		err = -EIO;
+		netdev_err(adapter->netdev, "Reset polling failed to complete.");
+	}
+
+	/* Double resets are required for recovery from certain error
+	 * conditions. Between resets, it is necessary to stall to allow time
+	 * for any pending HW events to complete.
+	 */
+	msleep(100);
+	if (hw->mac.flags & IXGBE_FLAGS_DOUBLE_RESET_REQUIRED) {
+		hw->mac.flags &= ~IXGBE_FLAGS_DOUBLE_RESET_REQUIRED;
+		goto mac_reset_top;
+	}
+
+	/* Set the Rx packet buffer size. */
+	IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(0), GENMASK(18, 17));
+
+	/* Store the permanent mac address */
+	hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr);
+
+	/* Maximum number of Receive Address Registers. */
+#define IXGBE_MAX_NUM_RAR		128
+
+	/* Store MAC address from RAR0, clear receive address registers, and
+	 * clear the multicast table.  Also reset num_rar_entries to the
+	 * maximum number of Receive Address Registers, since we modify this
+	 * value when programming the SAN MAC address.
+	 */
+	hw->mac.num_rar_entries = IXGBE_MAX_NUM_RAR;
+	hw->mac.ops.init_rx_addrs(hw);
+
+	/* Initialize bus function number */
+	hw->mac.ops.set_lan_id(hw);
+
+reset_hw_out:
+	return err;
+}
+
+static const struct ixgbe_mac_operations mac_ops_e610 = {
+	.init_hw			= ixgbe_init_hw_generic,
+	.start_hw			= ixgbe_start_hw_X540,
+	.clear_hw_cntrs			= ixgbe_clear_hw_cntrs_generic,
+	.enable_rx_dma			= ixgbe_enable_rx_dma_generic,
+	.get_mac_addr			= ixgbe_get_mac_addr_generic,
+	.get_device_caps		= ixgbe_get_device_caps_generic,
+	.stop_adapter			= ixgbe_stop_adapter_generic,
+	.set_lan_id			= ixgbe_set_lan_id_multi_port_pcie,
+	.set_rxpba			= ixgbe_set_rxpba_generic,
+	.check_link			= ixgbe_check_link_e610,
+	.blink_led_start		= ixgbe_blink_led_start_X540,
+	.blink_led_stop			= ixgbe_blink_led_stop_X540,
+	.set_rar			= ixgbe_set_rar_generic,
+	.clear_rar			= ixgbe_clear_rar_generic,
+	.set_vmdq			= ixgbe_set_vmdq_generic,
+	.set_vmdq_san_mac		= ixgbe_set_vmdq_san_mac_generic,
+	.clear_vmdq			= ixgbe_clear_vmdq_generic,
+	.init_rx_addrs			= ixgbe_init_rx_addrs_generic,
+	.update_mc_addr_list		= ixgbe_update_mc_addr_list_generic,
+	.enable_mc			= ixgbe_enable_mc_generic,
+	.disable_mc			= ixgbe_disable_mc_generic,
+	.clear_vfta			= ixgbe_clear_vfta_generic,
+	.set_vfta			= ixgbe_set_vfta_generic,
+	.fc_enable			= ixgbe_fc_enable_generic,
+	.set_fw_drv_ver			= ixgbe_set_fw_drv_ver_x550,
+	.init_uta_tables		= ixgbe_init_uta_tables_generic,
+	.set_mac_anti_spoofing		= ixgbe_set_mac_anti_spoofing,
+	.set_vlan_anti_spoofing		= ixgbe_set_vlan_anti_spoofing,
+	.set_source_address_pruning	=
+				ixgbe_set_source_address_pruning_x550,
+	.set_ethertype_anti_spoofing	=
+				ixgbe_set_ethertype_anti_spoofing_x550,
+	.disable_rx_buff		= ixgbe_disable_rx_buff_generic,
+	.enable_rx_buff			= ixgbe_enable_rx_buff_generic,
+	.enable_rx			= ixgbe_enable_rx_generic,
+	.disable_rx			= ixgbe_disable_rx_e610,
+	.led_on				= ixgbe_led_on_generic,
+	.led_off			= ixgbe_led_off_generic,
+	.init_led_link_act		= ixgbe_init_led_link_act_generic,
+	.reset_hw			= ixgbe_reset_hw_e610,
+	.get_media_type			= ixgbe_get_media_type_e610,
+	.setup_link			= ixgbe_setup_link_e610,
+	.get_link_capabilities		= ixgbe_get_link_capabilities_e610,
+	.get_bus_info			= ixgbe_get_bus_info_generic,
+	.acquire_swfw_sync		= ixgbe_acquire_swfw_sync_X540,
+	.release_swfw_sync		= ixgbe_release_swfw_sync_X540,
+	.init_swfw_sync			= ixgbe_init_swfw_sync_X540,
+	.prot_autoc_read		= prot_autoc_read_generic,
+	.prot_autoc_write		= prot_autoc_write_generic,
+	.setup_fc			= ixgbe_setup_fc_e610,
+	.fc_autoneg			= ixgbe_fc_autoneg_e610,
+};
+
+static const struct ixgbe_phy_operations phy_ops_e610 = {
+	.init				= ixgbe_init_phy_ops_e610,
+	.identify			= ixgbe_identify_phy_e610,
+	.identify_sfp			= ixgbe_identify_module_e610,
+	.setup_link_speed		= ixgbe_setup_phy_link_speed_generic,
+	.setup_link			= ixgbe_setup_phy_link_e610,
+	.enter_lplu			= ixgbe_enter_lplu_e610,
+};
+
+static const struct ixgbe_eeprom_operations eeprom_ops_e610 = {
+	.read				= ixgbe_read_ee_aci_e610,
+	.validate_checksum		= ixgbe_validate_eeprom_checksum_e610,
+};
+
+const struct ixgbe_info ixgbe_e610_info = {
+	.mac			= ixgbe_mac_e610,
+	.get_invariants		= ixgbe_get_invariants_X540,
+	.mac_ops		= &mac_ops_e610,
+	.eeprom_ops		= &eeprom_ops_e610,
+	.phy_ops		= &phy_ops_e610,
+	.mbx_ops		= &mbx_ops_generic,
+	.mvals			= ixgbe_mvals_x550em_a,
+};
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
index 412ddd1..8c4eaa74 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
@@ -71,5 +71,6 @@ int ixgbe_read_flat_nvm(struct ixgbe_hw  *hw, u32 offset, u32 *length,
 			u8 *data, bool read_shadow_ram);
 int ixgbe_read_ee_aci_e610(struct ixgbe_hw *hw, u16 offset, u16 *data);
 int ixgbe_validate_eeprom_checksum_e610(struct ixgbe_hw *hw, u16 *checksum_val);
+int ixgbe_reset_hw_e610(struct ixgbe_hw *hw);
 
 #endif /* _IXGBE_E610_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index 9482e0c..da91c58 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Copyright(c) 1999 - 2018 Intel Corporation. */
+/* Copyright(c) 1999 - 2024 Intel Corporation. */
 
 /* ethtool support for ixgbe */
 
@@ -690,6 +690,7 @@ static void ixgbe_get_regs(struct net_device *netdev,
 		case ixgbe_mac_X550:
 		case ixgbe_mac_X550EM_x:
 		case ixgbe_mac_x550em_a:
+		case ixgbe_mac_e610:
 			regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTL_82599(i));
 			regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH_82599(i));
 			break;
@@ -1613,6 +1614,7 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		toggle = 0x7FFFF30F;
 		test = reg_test_82599;
 		break;
@@ -1874,6 +1876,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_DMATXCTL);
 		reg_data |= IXGBE_DMATXCTL_TE;
 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_DMATXCTL, reg_data);
@@ -1935,6 +1938,7 @@ static int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		reg_data = IXGBE_READ_REG(hw, IXGBE_MACC);
 		reg_data |= IXGBE_MACC_FLU;
 		IXGBE_WRITE_REG(hw, IXGBE_MACC, reg_data);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
index 16fa621..336d47f 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Copyright(c) 1999 - 2018 Intel Corporation. */
+/* Copyright(c) 1999 - 2024 Intel Corporation. */
 
 #include "ixgbe.h"
 #include "ixgbe_sriov.h"
@@ -107,6 +107,7 @@ static void ixgbe_get_first_reg_idx(struct ixgbe_adapter *adapter, u8 tc,
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		if (num_tcs > 4) {
 			/*
 			 * TCs    : TC0/1 TC2/3 TC4-7
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 6bf5adcb..782a544 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Copyright(c) 1999 - 2018 Intel Corporation. */
+/* Copyright(c) 1999 - 2024 Intel Corporation. */
 
 #include <linux/types.h>
 #include <linux/module.h>
@@ -73,6 +73,7 @@ static const struct ixgbe_info *ixgbe_info_tbl[] = {
 	[board_x550em_x_fw]	= &ixgbe_x550em_x_fw_info,
 	[board_x550em_a]	= &ixgbe_x550em_a_info,
 	[board_x550em_a_fw]	= &ixgbe_x550em_a_fw_info,
+	[board_e610]		= &ixgbe_e610_info,
 };
 
 /* ixgbe_pci_tbl - PCI Device ID Table
@@ -131,6 +132,11 @@ static const struct pci_device_id ixgbe_pci_tbl[] = {
 	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SFP), board_x550em_a },
 	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_1G_T), board_x550em_a_fw },
 	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_1G_T_L), board_x550em_a_fw },
+	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_BACKPLANE), board_e610},
+	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_SFP), board_e610},
+	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_10G_T), board_e610},
+	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_2_5G_T), board_e610},
+	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_SGMII), board_e610},
 	/* required last entry */
 	{0, }
 };
@@ -173,6 +179,8 @@ static struct workqueue_struct *ixgbe_wq;
 
 static bool ixgbe_check_cfg_remove(struct ixgbe_hw *hw, struct pci_dev *pdev);
 static void ixgbe_watchdog_link_is_down(struct ixgbe_adapter *);
+static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *);
+static void ixgbe_watchdog_update_link(struct ixgbe_adapter *);
 
 static const struct net_device_ops ixgbe_netdev_ops;
 
@@ -240,7 +248,7 @@ static int ixgbe_get_parent_bus_info(struct ixgbe_adapter *adapter)
  * Return: true if information should be collected from the parent bus, false
  *         otherwise
  */
-static inline bool ixgbe_pcie_from_parent(struct ixgbe_hw *hw)
+static bool ixgbe_pcie_from_parent(struct ixgbe_hw *hw)
 {
 	switch (hw->device_id) {
 	case IXGBE_DEV_ID_82599_SFP_SF_QP:
@@ -879,6 +887,7 @@ static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, s8 direction,
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		if (direction == -1) {
 			/* other causes */
 			msix_vector |= IXGBE_IVAR_ALLOC_VAL;
@@ -918,6 +927,7 @@ void ixgbe_irq_rearm_queues(struct ixgbe_adapter *adapter,
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		mask = (qmask & 0xFFFFFFFF);
 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask);
 		mask = (qmask >> 32);
@@ -1028,7 +1038,7 @@ static u64 ixgbe_get_tx_pending(struct ixgbe_ring *ring)
 	return ((head <= tail) ? tail : tail + ring->count) - head;
 }
 
-static inline bool ixgbe_check_tx_hang(struct ixgbe_ring *tx_ring)
+static bool ixgbe_check_tx_hang(struct ixgbe_ring *tx_ring)
 {
 	u32 tx_done = ixgbe_get_tx_completed(tx_ring);
 	u32 tx_done_old = tx_ring->tx_stats.tx_done_old;
@@ -2518,6 +2528,7 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		ixgbe_set_ivar(adapter, -1, 1, v_idx);
 		break;
 	default:
@@ -2531,6 +2542,9 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
 		  IXGBE_EIMS_MAILBOX |
 		  IXGBE_EIMS_LSC);
 
+	if (adapter->hw.mac.type == ixgbe_mac_e610)
+		mask &= ~IXGBE_EIMS_FW_EVENT;
+
 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, mask);
 }
 
@@ -2747,6 +2761,7 @@ void ixgbe_write_eitr(struct ixgbe_q_vector *q_vector)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		/*
 		 * set the WDIS bit to not clear the timer bits and cause an
 		 * immediate assertion of the interrupt
@@ -2969,6 +2984,218 @@ static void ixgbe_check_lsc(struct ixgbe_adapter *adapter)
 	}
 }
 
+/**
+ * ixgbe_check_phy_fw_load - check if PHY FW load failed
+ * @adapter: pointer to adapter structure
+ * @link_cfg_err: bitmap from the link info structure
+ *
+ * Check if external PHY FW load failed and print an error message if it did.
+ */
+static void ixgbe_check_phy_fw_load(struct ixgbe_adapter *adapter,
+				    u8 link_cfg_err)
+{
+	if (!(link_cfg_err & IXGBE_ACI_LINK_EXTERNAL_PHY_LOAD_FAILURE)) {
+		adapter->flags2 &= ~IXGBE_FLAG2_PHY_FW_LOAD_FAILED;
+		return;
+	}
+
+	if (adapter->flags2 & IXGBE_FLAG2_PHY_FW_LOAD_FAILED)
+		return;
+
+	if (link_cfg_err & IXGBE_ACI_LINK_EXTERNAL_PHY_LOAD_FAILURE) {
+		netdev_err(adapter->netdev, "Device failed to load the FW for the external PHY. Please download and install the latest NVM for your device and try again\n");
+		adapter->flags2 |= IXGBE_FLAG2_PHY_FW_LOAD_FAILED;
+	}
+}
+
+/**
+ * ixgbe_check_module_power - check module power level
+ * @adapter: pointer to adapter structure
+ * @link_cfg_err: bitmap from the link info structure
+ *
+ * Check module power level returned by a previous call to aci_get_link_info
+ * and print error messages if module power level is not supported.
+ */
+static void ixgbe_check_module_power(struct ixgbe_adapter *adapter,
+				     u8 link_cfg_err)
+{
+	/* If module power level is supported, clear the flag. */
+	if (!(link_cfg_err & (IXGBE_ACI_LINK_INVAL_MAX_POWER_LIMIT |
+			      IXGBE_ACI_LINK_MODULE_POWER_UNSUPPORTED))) {
+		adapter->flags2 &= ~IXGBE_FLAG2_MOD_POWER_UNSUPPORTED;
+		return;
+	}
+
+	/* If IXGBE_FLAG2_MOD_POWER_UNSUPPORTED was previously set and the
+	 * above block didn't clear this bit, there's nothing to do.
+	 */
+	if (adapter->flags2 & IXGBE_FLAG2_MOD_POWER_UNSUPPORTED)
+		return;
+
+	if (link_cfg_err & IXGBE_ACI_LINK_INVAL_MAX_POWER_LIMIT) {
+		netdev_err(adapter->netdev, "The installed module is incompatible with the device's NVM image. Cannot start link.\n");
+		adapter->flags2 |= IXGBE_FLAG2_MOD_POWER_UNSUPPORTED;
+	} else if (link_cfg_err & IXGBE_ACI_LINK_MODULE_POWER_UNSUPPORTED) {
+		netdev_err(adapter->netdev, "The module's power requirements exceed the device's power supply. Cannot start link.\n");
+		adapter->flags2 |= IXGBE_FLAG2_MOD_POWER_UNSUPPORTED;
+	}
+}
+
+/**
+ * ixgbe_check_link_cfg_err - check if link configuration failed
+ * @adapter: pointer to adapter structure
+ * @link_cfg_err: bitmap from the link info structure
+ *
+ * Print if any link configuration failure happens due to the value in the
+ * link_cfg_err parameter in the link info structure.
+ */
+static void ixgbe_check_link_cfg_err(struct ixgbe_adapter *adapter,
+				     u8 link_cfg_err)
+{
+	ixgbe_check_module_power(adapter, link_cfg_err);
+	ixgbe_check_phy_fw_load(adapter, link_cfg_err);
+}
+
+/**
+ * ixgbe_process_link_status_event - process the link event
+ * @adapter: pointer to adapter structure
+ * @link_up: true if the physical link is up and false if it is down
+ * @link_speed: current link speed received from the link event
+ *
+ * Return: 0 on success or negative value on failure.
+ */
+static int
+ixgbe_process_link_status_event(struct ixgbe_adapter *adapter, bool link_up,
+				u16 link_speed)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+	int status;
+
+	/* Update the link info structures and re-enable link events,
+	 * don't bail on failure due to other book keeping needed.
+	 */
+	status = ixgbe_update_link_info(hw);
+	if (status)
+		e_dev_err("Failed to update link status, err %d aq_err %d\n",
+			  status, hw->aci.last_status);
+
+	ixgbe_check_link_cfg_err(adapter, hw->link.link_info.link_cfg_err);
+
+	/* Check if the link state is up after updating link info, and treat
+	 * this event as an UP event since the link is actually UP now.
+	 */
+	if (hw->link.link_info.link_info & IXGBE_ACI_LINK_UP)
+		link_up = true;
+
+	/* Turn off PHY if media was removed. */
+	if (!(adapter->flags2 & IXGBE_FLAG2_NO_MEDIA) &&
+	    !(hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE))
+		adapter->flags2 |= IXGBE_FLAG2_NO_MEDIA;
+
+	if (link_up == adapter->link_up &&
+	    link_up == netif_carrier_ok(adapter->netdev))
+		return 0;
+
+	if (link_up)
+		ixgbe_watchdog_link_is_up(adapter);
+	else
+		ixgbe_watchdog_link_is_down(adapter);
+
+	if (link_speed != adapter->link_speed) {
+		adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
+		ixgbe_watchdog_update_link(adapter);
+	}
+
+	return 0;
+}
+
+/**
+ * ixgbe_handle_link_status_event - handle link status event via ACI
+ * @adapter: pointer to adapter structure
+ * @e: event structure containing link status info
+ */
+static void
+ixgbe_handle_link_status_event(struct ixgbe_adapter *adapter,
+			       struct ixgbe_aci_event *e)
+{
+	struct ixgbe_aci_cmd_get_link_status_data *link_data;
+	u16 link_speed;
+	bool link_up;
+
+	link_data = (struct ixgbe_aci_cmd_get_link_status_data *)e->msg_buf;
+
+	link_up = !!(link_data->link_info & IXGBE_ACI_LINK_UP);
+	link_speed = link_data->link_speed;
+
+	if (ixgbe_process_link_status_event(adapter, link_up, link_speed))
+		e_dev_warn("Could not process link status event");
+}
+
+/**
+ * ixgbe_schedule_fw_event - schedule Firmware event
+ * @adapter: pointer to the adapter structure
+ *
+ * If the adapter is not in down, removing or resetting state,
+ * an event is scheduled.
+ */
+static void ixgbe_schedule_fw_event(struct ixgbe_adapter *adapter)
+{
+	if (!test_bit(__IXGBE_DOWN, &adapter->state) &&
+	    !test_bit(__IXGBE_REMOVING, &adapter->state) &&
+	    !test_bit(__IXGBE_RESETTING, &adapter->state)) {
+		adapter->flags2 |= IXGBE_FLAG2_FW_ASYNC_EVENT;
+		ixgbe_service_event_schedule(adapter);
+	}
+}
+
+/**
+ * ixgbe_aci_event_cleanup - release msg_buf memory
+ * @event: pointer to the event holding msg_buf to be released
+ *
+ * Clean memory allocated for event's msg_buf. Implements auto memory cleanup.
+ */
+static void ixgbe_aci_event_cleanup(struct ixgbe_aci_event *event)
+{
+	kfree(event->msg_buf);
+}
+
+/**
+ * ixgbe_handle_fw_event - handle Firmware event
+ * @adapter: pointer to the adapter structure
+ *
+ * Obtain an event from the ACI and then and then process it according to the
+ * type of the event and the opcode.
+ */
+static void ixgbe_handle_fw_event(struct ixgbe_adapter *adapter)
+{
+	struct ixgbe_aci_event event __cleanup(ixgbe_aci_event_cleanup);
+	struct ixgbe_hw *hw = &adapter->hw;
+	bool pending = false;
+	int err;
+
+	if (adapter->flags2 & IXGBE_FLAG2_FW_ASYNC_EVENT)
+		adapter->flags2 &= ~IXGBE_FLAG2_FW_ASYNC_EVENT;
+	event.buf_len = IXGBE_ACI_MAX_BUFFER_SIZE;
+	event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL);
+	if (!event.msg_buf)
+		return;
+
+	do {
+		err = ixgbe_aci_get_event(hw, &event, &pending);
+		if (err)
+			break;
+
+		switch (event.desc.opcode) {
+		case ixgbe_aci_opc_get_link_status:
+			ixgbe_handle_link_status_event(adapter, &event);
+			break;
+		default:
+			e_warn(hw, "unknown FW async event captured\n");
+			break;
+		}
+	} while (pending);
+}
+
 static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter,
 					   u64 qmask)
 {
@@ -2985,6 +3212,7 @@ static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter,
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		mask = (qmask & 0xFFFFFFFF);
 		if (mask)
 			IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask);
@@ -3038,6 +3266,9 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter, bool queues,
 	case ixgbe_mac_X540:
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
+	case ixgbe_mac_e610:
+		mask |= IXGBE_EIMS_FW_EVENT;
+		fallthrough;
 	case ixgbe_mac_x550em_a:
 		if (adapter->hw.device_id == IXGBE_DEV_ID_X550EM_X_SFP ||
 		    adapter->hw.device_id == IXGBE_DEV_ID_X550EM_A_SFP ||
@@ -3094,12 +3325,16 @@ static irqreturn_t ixgbe_msix_other(int irq, void *data)
 	if (eicr & IXGBE_EICR_MAILBOX)
 		ixgbe_msg_task(adapter);
 
+	if (eicr & IXGBE_EICR_FW_EVENT)
+		ixgbe_schedule_fw_event(adapter);
+
 	switch (hw->mac.type) {
 	case ixgbe_mac_82599EB:
 	case ixgbe_mac_X540:
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		if (hw->phy.type == ixgbe_phy_x550em_ext_t &&
 		    (eicr & IXGBE_EICR_GPI_SDP0_X540)) {
 			adapter->flags2 |= IXGBE_FLAG2_PHY_INTERRUPT;
@@ -3337,6 +3572,9 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
 	if (eicr & IXGBE_EICR_LSC)
 		ixgbe_check_lsc(adapter);
 
+	if (eicr & IXGBE_EICR_FW_EVENT)
+		ixgbe_schedule_fw_event(adapter);
+
 	switch (hw->mac.type) {
 	case ixgbe_mac_82599EB:
 		ixgbe_check_sfp_event(adapter, eicr);
@@ -3345,6 +3583,7 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		if (eicr & IXGBE_EICR_ECC) {
 			e_info(link, "Received ECC Err, initiating reset\n");
 			set_bit(__IXGBE_RESET_REQUESTED, &adapter->state);
@@ -3445,6 +3684,7 @@ static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000);
 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0);
 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0);
@@ -4362,6 +4602,7 @@ static void ixgbe_setup_rdrxctl(struct ixgbe_adapter *adapter)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		if (adapter->num_vfs)
 			rdrxctl |= IXGBE_RDRXCTL_PSP;
 		fallthrough;
@@ -4529,6 +4770,7 @@ static void ixgbe_vlan_strip_disable(struct ixgbe_adapter *adapter)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		for (i = 0; i < adapter->num_rx_queues; i++) {
 			struct ixgbe_ring *ring = adapter->rx_ring[i];
 
@@ -4567,6 +4809,7 @@ static void ixgbe_vlan_strip_enable(struct ixgbe_adapter *adapter)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		for (i = 0; i < adapter->num_rx_queues; i++) {
 			struct ixgbe_ring *ring = adapter->rx_ring[i];
 
@@ -5151,6 +5394,7 @@ static int ixgbe_hpbthresh(struct ixgbe_adapter *adapter, int pb)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		dv_id = IXGBE_DV_X540(link, tc);
 		break;
 	default:
@@ -5211,6 +5455,7 @@ static int ixgbe_lpbthresh(struct ixgbe_adapter *adapter, int pb)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		dv_id = IXGBE_LOW_DV_X540(tc);
 		break;
 	default:
@@ -5512,6 +5757,48 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter)
 	ixgbe_configure_dfwd(adapter);
 }
 
+/**
+ * ixgbe_enable_link_status_events - enable link status events
+ * @adapter: pointer to the adapter structure
+ * @mask: event mask to be set
+ *
+ * Enables link status events by invoking ixgbe_configure_lse()
+ *
+ * Return: the exit code of the operation.
+ */
+static int ixgbe_enable_link_status_events(struct ixgbe_adapter *adapter,
+					   u16 mask)
+{
+	int err;
+
+	err = ixgbe_configure_lse(&adapter->hw, true, mask);
+	if (err)
+		return err;
+
+	adapter->lse_mask = mask;
+	return 0;
+}
+
+/**
+ * ixgbe_disable_link_status_events - disable link status events
+ * @adapter: pointer to the adapter structure
+ *
+ * Disables link status events by invoking ixgbe_configure_lse()
+ *
+ * Return: the exit code of the operation.
+ */
+static int ixgbe_disable_link_status_events(struct ixgbe_adapter *adapter)
+{
+	int err;
+
+	err = ixgbe_configure_lse(&adapter->hw, false, adapter->lse_mask);
+	if (err)
+		return err;
+
+	adapter->lse_mask = 0;
+	return 0;
+}
+
 /**
  * ixgbe_sfp_link_config - set up SFP+ link
  * @adapter: pointer to private adapter struct
@@ -5541,9 +5828,15 @@ static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter)
  **/
 static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw)
 {
-	u32 speed;
+	struct ixgbe_adapter *adapter = container_of(hw, struct ixgbe_adapter,
+						     hw);
+	u16 mask = ~((u16)(IXGBE_ACI_LINK_EVENT_UPDOWN |
+			   IXGBE_ACI_LINK_EVENT_MEDIA_NA |
+			   IXGBE_ACI_LINK_EVENT_MODULE_QUAL_FAIL |
+			   IXGBE_ACI_LINK_EVENT_PHY_FW_LOAD_FAIL));
 	bool autoneg, link_up = false;
 	int ret = -EIO;
+	u32 speed;
 
 	if (hw->mac.ops.check_link)
 		ret = hw->mac.ops.check_link(hw, &speed, &link_up, false);
@@ -5566,12 +5859,52 @@ static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw)
 	if (ret)
 		return ret;
 
-	if (hw->mac.ops.setup_link)
+	if (hw->mac.ops.setup_link) {
+		if (adapter->hw.mac.type == ixgbe_mac_e610) {
+			ret = ixgbe_enable_link_status_events(adapter, mask);
+			if (ret)
+				return ret;
+		}
 		ret = hw->mac.ops.setup_link(hw, speed, link_up);
+	}
 
 	return ret;
 }
 
+/**
+ * ixgbe_check_media_subtask - check for media
+ * @adapter: pointer to adapter structure
+ *
+ * If media is available then initialize PHY user configuration. Configure the
+ * PHY if the interface is up.
+ */
+static void ixgbe_check_media_subtask(struct ixgbe_adapter *adapter)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+
+	/* No need to check for media if it's already present */
+	if (!(adapter->flags2 & IXGBE_FLAG2_NO_MEDIA))
+		return;
+
+	/* Refresh link info and check if media is present */
+	if (ixgbe_update_link_info(hw))
+		return;
+
+	ixgbe_check_link_cfg_err(adapter, hw->link.link_info.link_cfg_err);
+
+	if (hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE) {
+		/* PHY settings are reset on media insertion, reconfigure
+		 * PHY to preserve settings.
+		 */
+		if (!(ixgbe_non_sfp_link_config(&adapter->hw)))
+			adapter->flags2 &= ~IXGBE_FLAG2_NO_MEDIA;
+
+		/* A Link Status Event will be generated; the event handler
+		 * will complete bringing the interface up
+		 */
+	}
+}
+
 /**
  * ixgbe_clear_vf_stats_counters - Clear out VF stats after reset
  * @adapter: board private structure
@@ -5635,6 +5968,7 @@ static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter)
 		case ixgbe_mac_X550:
 		case ixgbe_mac_X550EM_x:
 		case ixgbe_mac_x550em_a:
+		case ixgbe_mac_e610:
 		default:
 			IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF);
 			IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF);
@@ -5985,6 +6319,7 @@ void ixgbe_disable_tx(struct ixgbe_adapter *adapter)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL,
 				(IXGBE_READ_REG(hw, IXGBE_DMATXCTL) &
 				 ~IXGBE_DMATXCTL_TE));
@@ -6229,6 +6564,8 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
 
 	ixgbe_clean_all_tx_rings(adapter);
 	ixgbe_clean_all_rx_rings(adapter);
+	if (adapter->hw.mac.type == ixgbe_mac_e610)
+		ixgbe_disable_link_status_events(adapter);
 }
 
 /**
@@ -6284,6 +6621,7 @@ static void ixgbe_init_dcb(struct ixgbe_adapter *adapter)
 		break;
 	case ixgbe_mac_X540:
 	case ixgbe_mac_X550:
+	case ixgbe_mac_e610:
 		adapter->dcb_cfg.num_tcs.pg_tcs = X540_TRAFFIC_CLASS;
 		adapter->dcb_cfg.num_tcs.pfc_tcs = X540_TRAFFIC_CLASS;
 		break;
@@ -6347,6 +6685,8 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter,
 	hw->subsystem_vendor_id = pdev->subsystem_vendor;
 	hw->subsystem_device_id = pdev->subsystem_device;
 
+	hw->mac.max_link_up_time = IXGBE_LINK_UP_TIME;
+
 	/* get_invariants needs the device IDs */
 	ii->get_invariants(hw);
 
@@ -6914,6 +7254,19 @@ int ixgbe_open(struct net_device *netdev)
 	ixgbe_up_complete(adapter);
 
 	udp_tunnel_nic_reset_ntf(netdev);
+	if (adapter->hw.mac.type == ixgbe_mac_e610) {
+		int err = ixgbe_update_link_info(&adapter->hw);
+
+		if (err)
+			e_dev_err("Failed to update link info, err %d.\n", err);
+
+		ixgbe_check_link_cfg_err(adapter,
+					 adapter->hw.link.link_info.link_cfg_err);
+
+		err = ixgbe_non_sfp_link_config(&adapter->hw);
+		if (ixgbe_non_sfp_link_config(&adapter->hw))
+			e_dev_err("Link setup failed, err %d.\n", err);
+	}
 
 	return 0;
 
@@ -7067,6 +7420,7 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		pci_wake_from_d3(pdev, !!wufc);
 		break;
 	default:
@@ -7214,6 +7568,7 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
 		case ixgbe_mac_X550:
 		case ixgbe_mac_X550EM_x:
 		case ixgbe_mac_x550em_a:
+		case ixgbe_mac_e610:
 			hwstats->pxonrxc[i] +=
 				IXGBE_READ_REG(hw, IXGBE_PXONRXCNT(i));
 			break;
@@ -7230,7 +7585,8 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
 		    hw->mac.type == ixgbe_mac_X540 ||
 		    hw->mac.type == ixgbe_mac_X550 ||
 		    hw->mac.type == ixgbe_mac_X550EM_x ||
-		    hw->mac.type == ixgbe_mac_x550em_a) {
+		    hw->mac.type == ixgbe_mac_x550em_a ||
+		    hw->mac.type == ixgbe_mac_e610) {
 			hwstats->qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC_L(i));
 			IXGBE_READ_REG(hw, IXGBE_QBTC_H(i)); /* to clear */
 			hwstats->qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC_L(i));
@@ -7256,6 +7612,7 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		/* OS2BMC stats are X540 and later */
 		hwstats->o2bgptc += IXGBE_READ_REG(hw, IXGBE_O2BGPTC);
 		hwstats->o2bspc += IXGBE_READ_REG(hw, IXGBE_O2BSPC);
@@ -7556,6 +7913,7 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 	case ixgbe_mac_82599EB: {
 		u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN);
 		u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG);
@@ -8057,6 +8415,11 @@ static void ixgbe_service_task(struct work_struct *work)
 		ixgbe_service_event_complete(adapter);
 		return;
 	}
+	if (adapter->hw.mac.type == ixgbe_mac_e610) {
+		if (adapter->flags2 & IXGBE_FLAG2_FW_ASYNC_EVENT)
+			ixgbe_handle_fw_event(adapter);
+		ixgbe_check_media_subtask(adapter);
+	}
 	ixgbe_reset_subtask(adapter);
 	ixgbe_phy_interrupt_subtask(adapter);
 	ixgbe_sfp_detection_subtask(adapter);
@@ -10775,6 +11138,24 @@ bool ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id,
 	return false;
 }
 
+/**
+ * ixgbe_set_fw_version_e610 - Set FW version specifically on E610 adapters
+ * @adapter: the adapter private structure
+ *
+ * This function is used by probe and ethtool to determine the FW version to
+ * format to display. The FW version is taken from the EEPROM/NVM.
+ *
+ */
+static void ixgbe_set_fw_version_e610(struct ixgbe_adapter *adapter)
+{
+	struct ixgbe_orom_info *orom = &adapter->hw.flash.orom;
+	struct ixgbe_nvm_info *nvm = &adapter->hw.flash.nvm;
+
+	snprintf(adapter->eeprom_id, sizeof(adapter->eeprom_id),
+		 "%x.%02x 0x%x %d.%d.%d", nvm->major, nvm->minor,
+		 nvm->eetrack, orom->major, orom->build, orom->patch);
+}
+
 /**
  * ixgbe_set_fw_version - Set FW version
  * @adapter: the adapter private structure
@@ -10787,6 +11168,11 @@ static void ixgbe_set_fw_version(struct ixgbe_adapter *adapter)
 	struct ixgbe_hw *hw = &adapter->hw;
 	struct ixgbe_nvm_version nvm_ver;
 
+	if (adapter->hw.mac.type == ixgbe_mac_e610) {
+		ixgbe_set_fw_version_e610(adapter);
+		return;
+	}
+
 	ixgbe_get_oem_prod_version(hw, &nvm_ver);
 	if (nvm_ver.oem_valid) {
 		snprintf(adapter->eeprom_id, sizeof(adapter->eeprom_id),
@@ -10873,6 +11259,8 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 #else
 		indices = IXGBE_MAX_RSS_INDICES;
 #endif
+	} else if (ii->mac == ixgbe_mac_e610) {
+		indices = IXGBE_MAX_RSS_INDICES_X550;
 	}
 
 	netdev = alloc_etherdev_mq(sizeof(struct ixgbe_adapter), indices);
@@ -10951,6 +11339,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	switch (adapter->hw.mac.type) {
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
+	case ixgbe_mac_e610:
 		netdev->udp_tunnel_nic_info = &ixgbe_udp_tunnels_x550;
 		break;
 	case ixgbe_mac_x550em_a:
@@ -10971,6 +11360,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_WUS, ~0);
 		break;
 	default:
@@ -11142,6 +11532,8 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	ether_addr_copy(hw->mac.addr, hw->mac.perm_addr);
 	ixgbe_mac_set_default_filter(adapter);
 
+	if (hw->mac.type == ixgbe_mac_e610)
+		mutex_init(&hw->aci.lock);
 	timer_setup(&adapter->service_timer, ixgbe_service_timer, 0);
 
 	if (ixgbe_removed(hw->hw_addr)) {
@@ -11287,6 +11679,8 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 err_register:
 	ixgbe_release_hw_control(adapter);
 	ixgbe_clear_interrupt_scheme(adapter);
+	if (hw->mac.type == ixgbe_mac_e610)
+		mutex_destroy(&adapter->hw.aci.lock);
 err_sw_init:
 	ixgbe_disable_sriov(adapter);
 	adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP;
@@ -11333,6 +11727,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
 	set_bit(__IXGBE_REMOVING, &adapter->state);
 	cancel_work_sync(&adapter->service_task);
 
+	if (adapter->hw.mac.type == ixgbe_mac_e610) {
+		ixgbe_disable_link_status_events(adapter);
+		mutex_destroy(&adapter->hw.aci.lock);
+	}
+
 	if (adapter->mii_bus)
 		mdiobus_unregister(adapter->mii_bus);
 
@@ -11464,6 +11863,9 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
 		case ixgbe_mac_x550em_a:
 			device_id = IXGBE_DEV_ID_X550EM_A_VF;
 			break;
+		case ixgbe_mac_e610:
+			device_id = IXGBE_DEV_ID_E610_VF;
+			break;
 		default:
 			device_id = 0;
 			break;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
index d67d77e..788b5af 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Copyright(c) 1999 - 2018 Intel Corporation. */
+/* Copyright(c) 1999 - 2024 Intel Corporation. */
 
 #include <linux/pci.h>
 #include <linux/delay.h>
@@ -283,6 +283,7 @@ static int ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, u16 vf_number)
 	case ixgbe_mac_X550:
 	case ixgbe_mac_X550EM_x:
 	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_e610:
 		vflre = IXGBE_READ_REG(hw, IXGBE_VFLREC(reg_offset));
 		break;
 	default:
@@ -407,6 +408,7 @@ void ixgbe_init_mbx_params_pf(struct ixgbe_hw *hw)
 	    hw->mac.type != ixgbe_mac_X550 &&
 	    hw->mac.type != ixgbe_mac_X550EM_x &&
 	    hw->mac.type != ixgbe_mac_x550em_a &&
+	    hw->mac.type != ixgbe_mac_e610 &&
 	    hw->mac.type != ixgbe_mac_X540)
 		return;
 
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
index 07eaa3c3..0a03a8b 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Copyright(c) 1999 - 2018 Intel Corporation. */
+/* Copyright(c) 1999 - 2024 Intel Corporation. */
 
 #include <linux/pci.h>
 #include <linux/delay.h>
@@ -1117,7 +1117,7 @@ int ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw)
 	hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
 			     MDIO_MMD_AN, &autoneg_reg);
 
-	if (hw->mac.type == ixgbe_mac_X550) {
+	if (hw->mac.type == ixgbe_mac_X550 || hw->mac.type == ixgbe_mac_e610) {
 		/* Set or unset auto-negotiation 5G advertisement */
 		autoneg_reg &= ~IXGBE_MII_5GBASE_T_ADVERTISE;
 		if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_5GB_FULL) &&
@@ -1233,6 +1233,7 @@ static int ixgbe_get_copper_speeds_supported(struct ixgbe_hw *hw)
 
 	switch (hw->mac.type) {
 	case ixgbe_mac_X550:
+	case ixgbe_mac_e610:
 		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_2_5GB_FULL;
 		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_5GB_FULL;
 		break;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
index f1ffa39..cb1a265 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Copyright(c) 1999 - 2018 Intel Corporation. */
+/* Copyright(c) 1999 - 2024 Intel Corporation. */
 
 #include <linux/pci.h>
 #include <linux/delay.h>
@@ -65,7 +65,9 @@ int ixgbe_setup_mac_link_X540(struct ixgbe_hw *hw, ixgbe_link_speed speed,
  *  Resets the hardware by resetting the transmit and receive units, masks
  *  and clears all interrupts, perform a PHY reset, and perform a link (MAC)
  *  reset.
- **/
+ *
+ *  Return: 0 on success or negative value on failure
+ */
 int ixgbe_reset_hw_X540(struct ixgbe_hw *hw)
 {
 	u32 swfw_mask = hw->phy.phy_semaphore_mask;
@@ -132,10 +134,14 @@ int ixgbe_reset_hw_X540(struct ixgbe_hw *hw)
 	hw->mac.num_rar_entries = IXGBE_X540_MAX_TX_QUEUES;
 	hw->mac.ops.init_rx_addrs(hw);
 
+	/* The following is not supported by E610. */
+	if (hw->mac.type == ixgbe_mac_e610)
+		return status;
+
 	/* Store the permanent SAN mac address */
 	hw->mac.ops.get_san_mac_addr(hw, hw->mac.san_addr);
 
-	/* Add the SAN MAC address to the RAR only if it's a valid address */
+	/* Add the SAN MAC address to RAR if it's a valid address */
 	if (is_valid_ether_addr(hw->mac.san_addr)) {
 		/* Save the SAN MAC RAR index */
 		hw->mac.san_mac_rar_index = hw->mac.num_rar_entries - 1;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
index 7eeafc9..b6d29fd 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
@@ -1,7 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Copyright(c) 1999 - 2018 Intel Corporation. */
+/* Copyright(c) 1999 - 2024 Intel Corporation. */
 
 #include "ixgbe_x540.h"
+#include "ixgbe_x550.h"
 #include "ixgbe_type.h"
 #include "ixgbe_common.h"
 #include "ixgbe_phy.h"
@@ -2769,9 +2770,9 @@ static int ixgbe_led_off_t_x550em(struct ixgbe_hw *hw, u32 led_idx)
  *  semaphore, -EIO when command fails or -ENIVAL when incorrect
  *  params passed.
  **/
-static int ixgbe_set_fw_drv_ver_x550(struct ixgbe_hw *hw, u8 maj, u8 min,
-				     u8 build, u8 sub, u16 len,
-				     const char *driver_ver)
+int ixgbe_set_fw_drv_ver_x550(struct ixgbe_hw *hw, u8 maj, u8 min,
+			      u8 build, u8 sub, u16 len,
+			      const char *driver_ver)
 {
 	struct ixgbe_hic_drv_info2 fw_cmd;
 	int ret_val;
@@ -3510,8 +3511,8 @@ static int ixgbe_reset_hw_X550em(struct ixgbe_hw *hw)
  *  @enable: enable or disable switch for Ethertype anti-spoofing
  *  @vf: Virtual Function pool - VF Pool to set for Ethertype anti-spoofing
  **/
-static void ixgbe_set_ethertype_anti_spoofing_x550(struct ixgbe_hw *hw,
-						   bool enable, int vf)
+void ixgbe_set_ethertype_anti_spoofing_x550(struct ixgbe_hw *hw,
+					    bool enable, int vf)
 {
 	int vf_target_reg = vf >> 3;
 	int vf_target_shift = vf % 8 + IXGBE_SPOOF_ETHERTYPEAS_SHIFT;
@@ -3531,9 +3532,9 @@ static void ixgbe_set_ethertype_anti_spoofing_x550(struct ixgbe_hw *hw,
  *  @enable: enable or disable source address pruning
  *  @pool: Rx pool to set source address pruning for
  **/
-static void ixgbe_set_source_address_pruning_x550(struct ixgbe_hw *hw,
-						  bool enable,
-						  unsigned int pool)
+void ixgbe_set_source_address_pruning_x550(struct ixgbe_hw *hw,
+					   bool enable,
+					   unsigned int pool)
 {
 	u64 pfflp;
 
@@ -4046,7 +4047,7 @@ static const u32 ixgbe_mvals_X550EM_x[IXGBE_MVALS_IDX_LIMIT] = {
 	IXGBE_MVALS_INIT(X550EM_x)
 };
 
-static const u32 ixgbe_mvals_x550em_a[IXGBE_MVALS_IDX_LIMIT] = {
+const u32 ixgbe_mvals_x550em_a[IXGBE_MVALS_IDX_LIMIT] = {
 	IXGBE_MVALS_INIT(X550EM_a)
 };
 
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.h
new file mode 100644
index 0000000..3e4092f
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Intel Corporation. */
+
+#ifndef _IXGBE_X550_H_
+#define _IXGBE_X550_H_
+
+#include "ixgbe_type.h"
+
+extern const u32 ixgbe_mvals_x550em_a[IXGBE_MVALS_IDX_LIMIT];
+
+int ixgbe_set_fw_drv_ver_x550(struct ixgbe_hw *hw, u8 maj, u8 min,
+			      u8 build, u8 sub, u16 len,
+			      const char *driver_ver);
+void ixgbe_set_source_address_pruning_x550(struct ixgbe_hw *hw,
+					   bool enable,
+					   unsigned int pool);
+void ixgbe_set_ethertype_anti_spoofing_x550(struct ixgbe_hw *hw,
+					    bool enable, int vf);
+
+#endif /* _IXGBE_X550_H_ */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH iwl-next v9 2/7] ixgbe: Add support for E610 device capabilities detection
  2024-10-03 14:16 ` [PATCH iwl-next v9 2/7] ixgbe: Add support for E610 device capabilities detection Piotr Kwapulinski
@ 2024-10-17  9:46   ` Simon Horman
  2024-10-18  3:06   ` Kalesh Anakkur Purayil
  1 sibling, 0 replies; 16+ messages in thread
From: Simon Horman @ 2024-10-17  9:46 UTC (permalink / raw)
  To: Piotr Kwapulinski
  Cc: intel-wired-lan, netdev, Stefan Wegrzyn, Jedrzej Jagielski,
	Jan Sokolowski

On Thu, Oct 03, 2024 at 04:16:45PM +0200, Piotr Kwapulinski wrote:
> Add low level support for E610 device capabilities detection. The
> capabilities are discovered via the Admin Command Interface. Discover the
> following capabilities:
> - function caps: vmdq, dcb, rss, rx/tx qs, msix, nvm, orom, reset
> - device caps: vsi, fdir, 1588
> - phy caps
> 
> Co-developed-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
> Signed-off-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
> Co-developed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
> Signed-off-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
> Reviewed-by: Jan Sokolowski <jan.sokolowski@intel.com>
> Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>

Reviewed-by: Simon Horman <horms@kernel.org>


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH iwl-next v9 3/7] ixgbe: Add link management support for E610 device
  2024-10-03 14:16 ` [PATCH iwl-next v9 3/7] ixgbe: Add link management support for E610 device Piotr Kwapulinski
@ 2024-10-17  9:46   ` Simon Horman
  2024-10-17 13:26   ` Kalesh Anakkur Purayil
  1 sibling, 0 replies; 16+ messages in thread
From: Simon Horman @ 2024-10-17  9:46 UTC (permalink / raw)
  To: Piotr Kwapulinski
  Cc: intel-wired-lan, netdev, Stefan Wegrzyn, Jedrzej Jagielski,
	Jan Glaza

On Thu, Oct 03, 2024 at 04:16:46PM +0200, Piotr Kwapulinski wrote:
> Add low level link management support for E610 device. Link management
> operations are handled via the Admin Command Interface. Add the following
> link management operations:
> - get link capabilities
> - set up link
> - get media type
> - get link status, link status events
> - link power management
> 
> Co-developed-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
> Signed-off-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
> Co-developed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
> Signed-off-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
> Reviewed-by: Jan Glaza <jan.glaza@intel.com>
> Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>

Reviewed-by: Simon Horman <horms@kernel.org>


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH iwl-next v9 5/7] ixgbe: Add ixgbe_x540 multiple header inclusion protection
  2024-10-03 14:16 ` [PATCH iwl-next v9 5/7] ixgbe: Add ixgbe_x540 multiple header inclusion protection Piotr Kwapulinski
@ 2024-10-17  9:47   ` Simon Horman
  0 siblings, 0 replies; 16+ messages in thread
From: Simon Horman @ 2024-10-17  9:47 UTC (permalink / raw)
  To: Piotr Kwapulinski; +Cc: intel-wired-lan, netdev

On Thu, Oct 03, 2024 at 04:16:48PM +0200, Piotr Kwapulinski wrote:
> Required to adopt x540 specific functions by E610 device.
> 
> Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>

Reviewed-by: Simon Horman <horms@kernel.org>


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH iwl-next v9 3/7] ixgbe: Add link management support for E610 device
  2024-10-03 14:16 ` [PATCH iwl-next v9 3/7] ixgbe: Add link management support for E610 device Piotr Kwapulinski
  2024-10-17  9:46   ` Simon Horman
@ 2024-10-17 13:26   ` Kalesh Anakkur Purayil
  2024-10-21  9:01     ` Kwapulinski, Piotr
  1 sibling, 1 reply; 16+ messages in thread
From: Kalesh Anakkur Purayil @ 2024-10-17 13:26 UTC (permalink / raw)
  To: Piotr Kwapulinski
  Cc: intel-wired-lan, netdev, Stefan Wegrzyn, Jedrzej Jagielski,
	Jan Glaza

[-- Attachment #1: Type: text/plain, Size: 47541 bytes --]

On Thu, Oct 3, 2024 at 7:49 PM Piotr Kwapulinski
<piotr.kwapulinski@intel.com> wrote:
>
> Add low level link management support for E610 device. Link management
> operations are handled via the Admin Command Interface. Add the following
> link management operations:
> - get link capabilities
> - set up link
> - get media type
> - get link status, link status events
> - link power management
>
> Co-developed-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
> Signed-off-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
> Co-developed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
> Signed-off-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
> Reviewed-by: Jan Glaza <jan.glaza@intel.com>
> Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>
> ---
>  drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 1091 +++++++++++++++++
>  drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h |   32 +
>  .../ethernet/intel/ixgbe/ixgbe_type_e610.h    |    1 +
>  3 files changed, 1124 insertions(+)
>
> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
> index 3bc88df..c0c740f 100644
> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
> @@ -1033,3 +1033,1094 @@ void ixgbe_copy_phy_caps_to_cfg(struct ixgbe_aci_cmd_get_phy_caps_data *caps,
>         cfg->module_compliance_enforcement =
>                 caps->module_compliance_enforcement;
>  }
> +
> +/**
> + * ixgbe_aci_set_phy_cfg - set PHY configuration
> + * @hw: pointer to the HW struct
> + * @cfg: structure with PHY configuration data to be set
> + *
> + * Set the various PHY configuration parameters supported on the Port
> + * using ACI command (0x0601).
> + * One or more of the Set PHY config parameters may be ignored in an MFP
> + * mode as the PF may not have the privilege to set some of the PHY Config
> + * parameters.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_aci_set_phy_cfg(struct ixgbe_hw *hw,
> +                         struct ixgbe_aci_cmd_set_phy_cfg_data *cfg)
> +{
> +       struct ixgbe_aci_desc desc;
> +       int err;
> +
> +       if (!cfg)
> +               return -EINVAL;
> +
> +       /* Ensure that only valid bits of cfg->caps can be turned on. */
> +       cfg->caps &= IXGBE_ACI_PHY_ENA_VALID_MASK;
> +
> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_set_phy_cfg);
> +       desc.params.set_phy.lport_num = hw->bus.func;
> +       desc.flags |= IXGBE_ACI_FLAG_RD;
> +
> +       err = ixgbe_aci_send_cmd(hw, &desc, cfg, sizeof(*cfg));
> +
[Kalesh] There is no need of an empty line here
> +       if (!err)
> +               hw->phy.curr_user_phy_cfg = *cfg;
> +
> +       return err;
> +}
> +
> +/**
> + * ixgbe_aci_set_link_restart_an - set up link and restart AN
> + * @hw: pointer to the HW struct
> + * @ena_link: if true: enable link, if false: disable link
> + *
> + * Function sets up the link and restarts the Auto-Negotiation over the link.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_aci_set_link_restart_an(struct ixgbe_hw *hw, bool ena_link)
> +{
> +       struct ixgbe_aci_cmd_restart_an *cmd;
> +       struct ixgbe_aci_desc desc;
> +
> +       cmd = &desc.params.restart_an;
> +
> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_restart_an);
> +
> +       cmd->cmd_flags = IXGBE_ACI_RESTART_AN_LINK_RESTART;
> +       cmd->lport_num = hw->bus.func;
> +       if (ena_link)
> +               cmd->cmd_flags |= IXGBE_ACI_RESTART_AN_LINK_ENABLE;
> +       else
> +               cmd->cmd_flags &= ~IXGBE_ACI_RESTART_AN_LINK_ENABLE;
> +
> +       return ixgbe_aci_send_cmd(hw, &desc, NULL, 0);
> +}
> +
> +/**
> + * ixgbe_is_media_cage_present - check if media cage is present
> + * @hw: pointer to the HW struct
> + *
> + * Identify presence of media cage using the ACI command (0x06E0).
> + *
> + * Return: true if media cage is present, else false. If no cage, then
> + * media type is backplane or BASE-T.
> + */
> +static bool ixgbe_is_media_cage_present(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_aci_cmd_get_link_topo *cmd;
> +       struct ixgbe_aci_desc desc;
> +
> +       cmd = &desc.params.get_link_topo;
> +
> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_link_topo);
> +
> +       cmd->addr.topo_params.node_type_ctx =
> +               FIELD_PREP(IXGBE_ACI_LINK_TOPO_NODE_CTX_M,
> +                          IXGBE_ACI_LINK_TOPO_NODE_CTX_PORT);
> +
> +       /* Set node type. */
> +       cmd->addr.topo_params.node_type_ctx |=
> +               FIELD_PREP(IXGBE_ACI_LINK_TOPO_NODE_TYPE_M,
> +                          IXGBE_ACI_LINK_TOPO_NODE_TYPE_CAGE);
> +
> +       /* Node type cage can be used to determine if cage is present. If AQC
> +        * returns error (ENOENT), then no cage present. If no cage present then
> +        * connection type is backplane or BASE-T.
> +        */
> +       return ixgbe_aci_get_netlist_node(hw, cmd, NULL, NULL);
> +}
> +
> +/**
> + * ixgbe_get_media_type_from_phy_type - Gets media type based on phy type
> + * @hw: pointer to the HW struct
> + *
> + * Try to identify the media type based on the phy type.
> + * If more than one media type, the ixgbe_media_type_unknown is returned.
> + * First, phy_type_low is checked, then phy_type_high.
> + * If none are identified, the ixgbe_media_type_unknown is returned
> + *
> + * Return: type of a media based on phy type in form of enum.
> + */
> +static enum ixgbe_media_type
> +ixgbe_get_media_type_from_phy_type(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_link_status *hw_link_info;
> +
> +       if (!hw)
> +               return ixgbe_media_type_unknown;
> +
> +       hw_link_info = &hw->link.link_info;
> +       if (hw_link_info->phy_type_low && hw_link_info->phy_type_high)
> +               /* If more than one media type is selected, report unknown */
> +               return ixgbe_media_type_unknown;
> +
> +       if (hw_link_info->phy_type_low) {
> +               /* 1G SGMII is a special case where some DA cable PHYs
> +                * may show this as an option when it really shouldn't
> +                * be since SGMII is meant to be between a MAC and a PHY
> +                * in a backplane. Try to detect this case and handle it
> +                */
> +               if (hw_link_info->phy_type_low == IXGBE_PHY_TYPE_LOW_1G_SGMII &&
> +                   (hw_link_info->module_type[IXGBE_ACI_MOD_TYPE_IDENT] ==
> +                   IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_ACTIVE ||
> +                   hw_link_info->module_type[IXGBE_ACI_MOD_TYPE_IDENT] ==
> +                   IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_PASSIVE))
> +                       return ixgbe_media_type_da;
> +
> +               switch (hw_link_info->phy_type_low) {
> +               case IXGBE_PHY_TYPE_LOW_1000BASE_SX:
> +               case IXGBE_PHY_TYPE_LOW_1000BASE_LX:
> +               case IXGBE_PHY_TYPE_LOW_10GBASE_SR:
> +               case IXGBE_PHY_TYPE_LOW_10GBASE_LR:
> +               case IXGBE_PHY_TYPE_LOW_25GBASE_SR:
> +               case IXGBE_PHY_TYPE_LOW_25GBASE_LR:
> +                       return ixgbe_media_type_fiber;
> +               case IXGBE_PHY_TYPE_LOW_10G_SFI_AOC_ACC:
> +               case IXGBE_PHY_TYPE_LOW_25G_AUI_AOC_ACC:
> +                       return ixgbe_media_type_fiber;
> +               case IXGBE_PHY_TYPE_LOW_100BASE_TX:
> +               case IXGBE_PHY_TYPE_LOW_1000BASE_T:
> +               case IXGBE_PHY_TYPE_LOW_2500BASE_T:
> +               case IXGBE_PHY_TYPE_LOW_5GBASE_T:
> +               case IXGBE_PHY_TYPE_LOW_10GBASE_T:
> +               case IXGBE_PHY_TYPE_LOW_25GBASE_T:
> +                       return ixgbe_media_type_copper;
> +               case IXGBE_PHY_TYPE_LOW_10G_SFI_DA:
> +               case IXGBE_PHY_TYPE_LOW_25GBASE_CR:
> +               case IXGBE_PHY_TYPE_LOW_25GBASE_CR_S:
> +               case IXGBE_PHY_TYPE_LOW_25GBASE_CR1:
> +                       return ixgbe_media_type_da;
> +               case IXGBE_PHY_TYPE_LOW_25G_AUI_C2C:
> +                       if (ixgbe_is_media_cage_present(hw))
> +                               return ixgbe_media_type_aui;
> +                       fallthrough;
> +               case IXGBE_PHY_TYPE_LOW_1000BASE_KX:
> +               case IXGBE_PHY_TYPE_LOW_2500BASE_KX:
> +               case IXGBE_PHY_TYPE_LOW_2500BASE_X:
> +               case IXGBE_PHY_TYPE_LOW_5GBASE_KR:
> +               case IXGBE_PHY_TYPE_LOW_10GBASE_KR_CR1:
> +               case IXGBE_PHY_TYPE_LOW_10G_SFI_C2C:
> +               case IXGBE_PHY_TYPE_LOW_25GBASE_KR:
> +               case IXGBE_PHY_TYPE_LOW_25GBASE_KR1:
> +               case IXGBE_PHY_TYPE_LOW_25GBASE_KR_S:
> +                       return ixgbe_media_type_backplane;
> +               }
> +       } else {
> +               switch (hw_link_info->phy_type_high) {
> +               case IXGBE_PHY_TYPE_HIGH_10BASE_T:
> +                       return ixgbe_media_type_copper;
> +               }
> +       }
> +       return ixgbe_media_type_unknown;
> +}
> +
> +/**
> + * ixgbe_update_link_info - update status of the HW network link
> + * @hw: pointer to the HW struct
> + *
> + * Update the status of the HW network link.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_update_link_info(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_link_status *li;
> +       int err;
> +
> +       if (!hw)
> +               return -EINVAL;
> +
> +       li = &hw->link.link_info;
> +
> +       err = ixgbe_aci_get_link_info(hw, true, NULL);
> +       if (err)
> +               return err;
> +
> +       if (li->link_info & IXGBE_ACI_MEDIA_AVAILABLE) {
[Kalesh] If you change the check as below, that would help code indentation:
if (!(li->link_info & IXGBE_ACI_MEDIA_AVAILABLE))
      return 0;
> +               struct ixgbe_aci_cmd_get_phy_caps_data __free(kfree) *pcaps;
> +
> +               pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
> +               if (!pcaps)
> +                       return -ENOMEM;
> +
> +               err = ixgbe_aci_get_phy_caps(hw, false,
> +                                            IXGBE_ACI_REPORT_TOPO_CAP_MEDIA,
> +                                            pcaps);
> +
> +               if (!err)
> +                       memcpy(li->module_type, &pcaps->module_type,
> +                              sizeof(li->module_type));
> +       }
> +
> +       return err;
> +}
> +
> +/**
> + * ixgbe_get_link_status - get status of the HW network link
> + * @hw: pointer to the HW struct
> + * @link_up: pointer to bool (true/false = linkup/linkdown)
> + *
> + * Variable link_up is true if link is up, false if link is down.
> + * The variable link_up is invalid if status is non zero. As a
> + * result of this call, link status reporting becomes enabled
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_get_link_status(struct ixgbe_hw *hw, bool *link_up)
> +{
> +       if (!hw || !link_up)
> +               return -EINVAL;
> +
> +       if (hw->link.get_link_info) {
> +               int err = ixgbe_update_link_info(hw);
> +
> +               if (err)
> +                       return err;
> +       }
> +
> +       *link_up = hw->link.link_info.link_info & IXGBE_ACI_LINK_UP;
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_aci_get_link_info - get the link status
> + * @hw: pointer to the HW struct
> + * @ena_lse: enable/disable LinkStatusEvent reporting
> + * @link: pointer to link status structure - optional
> + *
> + * Get the current Link Status using ACI command (0x607).
> + * The current link can be optionally provided to update
> + * the status.
> + *
> + * Return: the link status of the adapter.
> + */
> +int ixgbe_aci_get_link_info(struct ixgbe_hw *hw, bool ena_lse,
> +                           struct ixgbe_link_status *link)
> +{
> +       struct ixgbe_aci_cmd_get_link_status_data link_data = { 0 };
> +       struct ixgbe_aci_cmd_get_link_status *resp;
> +       struct ixgbe_link_status *li_old, *li;
> +       struct ixgbe_fc_info *hw_fc_info;
> +       struct ixgbe_aci_desc desc;
> +       bool tx_pause, rx_pause;
> +       u8 cmd_flags;
> +       int err;
> +
> +       if (!hw)
> +               return -EINVAL;
> +
> +       li_old = &hw->link.link_info_old;
> +       li = &hw->link.link_info;
> +       hw_fc_info = &hw->fc;
> +
> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_link_status);
> +       cmd_flags = (ena_lse) ? IXGBE_ACI_LSE_ENA : IXGBE_ACI_LSE_DIS;
> +       resp = &desc.params.get_link_status;
> +       resp->cmd_flags = cmd_flags;
> +       resp->lport_num = hw->bus.func;
> +
> +       err = ixgbe_aci_send_cmd(hw, &desc, &link_data, sizeof(link_data));
> +
[Kalesh] there is no need of empty line here
> +       if (err)
> +               return err;
> +
> +       /* Save off old link status information. */
> +       *li_old = *li;
> +
> +       /* Update current link status information. */
> +       li->link_speed = link_data.link_speed;
> +       li->phy_type_low = link_data.phy_type_low;
> +       li->phy_type_high = link_data.phy_type_high;
> +       li->link_info = link_data.link_info;
> +       li->link_cfg_err = link_data.link_cfg_err;
> +       li->an_info = link_data.an_info;
> +       li->ext_info = link_data.ext_info;
> +       li->max_frame_size = link_data.max_frame_size;
> +       li->fec_info = link_data.cfg & IXGBE_ACI_FEC_MASK;
> +       li->topo_media_conflict = link_data.topo_media_conflict;
> +       li->pacing = link_data.cfg & (IXGBE_ACI_CFG_PACING_M |
> +                                     IXGBE_ACI_CFG_PACING_TYPE_M);
> +
> +       /* Update fc info. */
> +       tx_pause = !!(link_data.an_info & IXGBE_ACI_LINK_PAUSE_TX);
> +       rx_pause = !!(link_data.an_info & IXGBE_ACI_LINK_PAUSE_RX);
> +       if (tx_pause && rx_pause)
> +               hw_fc_info->current_mode = ixgbe_fc_full;
> +       else if (tx_pause)
> +               hw_fc_info->current_mode = ixgbe_fc_tx_pause;
> +       else if (rx_pause)
> +               hw_fc_info->current_mode = ixgbe_fc_rx_pause;
> +       else
> +               hw_fc_info->current_mode = ixgbe_fc_none;
> +
> +       li->lse_ena = !!(resp->cmd_flags & IXGBE_ACI_LSE_IS_ENABLED);
> +
> +       /* Save link status information. */
> +       if (link)
> +               *link = *li;
> +
> +       /* Flag cleared so calling functions don't call AQ again. */
> +       hw->link.get_link_info = false;
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_aci_set_event_mask - set event mask
> + * @hw: pointer to the HW struct
> + * @port_num: port number of the physical function
> + * @mask: event mask to be set
> + *
> + * Set the event mask using ACI command (0x0613).
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_aci_set_event_mask(struct ixgbe_hw *hw, u8 port_num, u16 mask)
> +{
> +       struct ixgbe_aci_cmd_set_event_mask *cmd;
> +       struct ixgbe_aci_desc desc;
> +
> +       cmd = &desc.params.set_event_mask;
> +
> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_set_event_mask);
> +
> +       cmd->lport_num = port_num;
> +
> +       cmd->event_mask = mask;
> +       return ixgbe_aci_send_cmd(hw, &desc, NULL, 0);
> +}
> +
> +/**
> + * ixgbe_configure_lse - enable/disable link status events
> + * @hw: pointer to the HW struct
> + * @activate: true for enable lse, false otherwise
> + * @mask: event mask to be set; a set bit means deactivation of the
> + * corresponding event
> + *
> + * Set the event mask and then enable or disable link status events
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_configure_lse(struct ixgbe_hw *hw, bool activate, u16 mask)
> +{
> +       int err;
> +
> +       err = ixgbe_aci_set_event_mask(hw, (u8)hw->bus.func, mask);
> +       if (err)
> +               return err;
> +
> +       /* Enabling link status events generation by fw */
> +       err = ixgbe_aci_get_link_info(hw, activate, NULL);
[Kalesh] You can simplify this as:
return ixgbe_aci_get_link_info(hw, activate, NULL);
> +       if (err)
> +               return err;
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_get_media_type_e610 - Gets media type
> + * @hw: pointer to the HW struct
> + *
> + * In order to get the media type, the function gets PHY
> + * capabilities and later on use them to identify the PHY type
> + * checking phy_type_high and phy_type_low.
> + *
> + * Return: the type of media in form of ixgbe_media_type enum
> + * or ixgbe_media_type_unknown in case of an error.
> + */
> +enum ixgbe_media_type ixgbe_get_media_type_e610(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_aci_cmd_get_phy_caps_data pcaps;
> +       int rc;
> +
> +       rc = ixgbe_update_link_info(hw);
> +       if (rc)
> +               return ixgbe_media_type_unknown;
> +
> +       /* If there is no link but PHY (dongle) is available SW should use
> +        * Get PHY Caps admin command instead of Get Link Status, find most
> +        * significant bit that is set in PHY types reported by the command
> +        * and use it to discover media type.
> +        */
> +       if (!(hw->link.link_info.link_info & IXGBE_ACI_LINK_UP) &&
> +           (hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE)) {
> +               int highest_bit;
> +
> +               /* Get PHY Capabilities */
> +               rc = ixgbe_aci_get_phy_caps(hw, false,
> +                                           IXGBE_ACI_REPORT_TOPO_CAP_MEDIA,
> +                                           &pcaps);
> +               if (rc)
> +                       return ixgbe_media_type_unknown;
> +
> +               highest_bit = fls64(pcaps.phy_type_high);
> +               if (highest_bit) {
> +                       hw->link.link_info.phy_type_high =
> +                               BIT_ULL(highest_bit - 1);
> +                       hw->link.link_info.phy_type_low = 0;
> +               } else {
> +                       highest_bit = fls64(pcaps.phy_type_low);
> +                       if (highest_bit)
> +                               hw->link.link_info.phy_type_low =
> +                                       BIT_ULL(highest_bit - 1);
> +               }
> +       }
> +
> +       /* Based on link status or search above try to discover media type. */
> +       hw->phy.media_type = ixgbe_get_media_type_from_phy_type(hw);
> +
> +       return hw->phy.media_type;
> +}
> +
> +/**
> + * ixgbe_setup_link_e610 - Set up link
> + * @hw: pointer to hardware structure
> + * @speed: new link speed
> + * @autoneg_wait: true when waiting for completion is needed
> + *
> + * Set up the link with the specified speed.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_setup_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed speed,
> +                         bool autoneg_wait)
> +{
> +       /* Simply request FW to perform proper PHY setup */
> +       return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait);
> +}
> +
> +/**
> + * ixgbe_check_link_e610 - Determine link and speed status
> + * @hw: pointer to hardware structure
> + * @speed: pointer to link speed
> + * @link_up: true when link is up
> + * @link_up_wait_to_complete: bool used to wait for link up or not
> + *
> + * Determine if the link is up and the current link speed
> + * using ACI command (0x0607).
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_check_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
> +                         bool *link_up, bool link_up_wait_to_complete)
> +{
> +       int err;
> +       u32 i;
> +
> +       if (!speed || !link_up)
> +               return -EINVAL;
> +
> +       /* Set get_link_info flag to ensure that fresh
> +        * link information will be obtained from FW
> +        * by sending Get Link Status admin command.
> +        */
> +       hw->link.get_link_info = true;
> +
> +       /* Update link information in adapter context. */
> +       err = ixgbe_get_link_status(hw, link_up);
> +       if (err)
> +               return err;
> +
> +       /* Wait for link up if it was requested. */
> +       if (link_up_wait_to_complete && !(*link_up)) {
> +               for (i = 0; i < hw->mac.max_link_up_time; i++) {
> +                       msleep(100);
> +                       hw->link.get_link_info = true;
> +                       err = ixgbe_get_link_status(hw, link_up);
> +                       if (err)
> +                               return err;
> +                       if (*link_up)
> +                               break;
> +               }
> +       }
> +
> +       /* Use link information in adapter context updated by the call
> +        * to ixgbe_get_link_status() to determine current link speed.
> +        * Link speed information is valid only when link up was
> +        * reported by FW.
> +        */
> +       if (*link_up) {
> +               switch (hw->link.link_info.link_speed) {
> +               case IXGBE_ACI_LINK_SPEED_10MB:
> +                       *speed = IXGBE_LINK_SPEED_10_FULL;
> +                       break;
> +               case IXGBE_ACI_LINK_SPEED_100MB:
> +                       *speed = IXGBE_LINK_SPEED_100_FULL;
> +                       break;
> +               case IXGBE_ACI_LINK_SPEED_1000MB:
> +                       *speed = IXGBE_LINK_SPEED_1GB_FULL;
> +                       break;
> +               case IXGBE_ACI_LINK_SPEED_2500MB:
> +                       *speed = IXGBE_LINK_SPEED_2_5GB_FULL;
> +                       break;
> +               case IXGBE_ACI_LINK_SPEED_5GB:
> +                       *speed = IXGBE_LINK_SPEED_5GB_FULL;
> +                       break;
> +               case IXGBE_ACI_LINK_SPEED_10GB:
> +                       *speed = IXGBE_LINK_SPEED_10GB_FULL;
> +                       break;
> +               default:
> +                       *speed = IXGBE_LINK_SPEED_UNKNOWN;
> +                       break;
> +               }
> +       } else {
> +               *speed = IXGBE_LINK_SPEED_UNKNOWN;
> +       }
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_get_link_capabilities_e610 - Determine link capabilities
> + * @hw: pointer to hardware structure
> + * @speed: pointer to link speed
> + * @autoneg: true when autoneg or autotry is enabled
> + *
> + * Determine speed and AN parameters of a link.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_get_link_capabilities_e610(struct ixgbe_hw *hw,
> +                                    ixgbe_link_speed *speed,
> +                                    bool *autoneg)
> +{
> +       if (!speed || !autoneg)
> +               return -EINVAL;
> +
> +       *autoneg = true;
> +       *speed = hw->phy.speeds_supported;
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_cfg_phy_fc - Configure PHY Flow Control (FC) data based on FC mode
> + * @hw: pointer to hardware structure
> + * @cfg: PHY configuration data to set FC mode
> + * @req_mode: FC mode to configure
> + *
> + * Configures PHY Flow Control according to the provided configuration.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_cfg_phy_fc(struct ixgbe_hw *hw,
> +                    struct ixgbe_aci_cmd_set_phy_cfg_data *cfg,
> +                    enum ixgbe_fc_mode req_mode)
> +{
> +       u8 pause_mask = 0x0;
> +
> +       if (!cfg)
> +               return -EINVAL;
> +
> +       switch (req_mode) {
> +       case ixgbe_fc_full:
> +               pause_mask |= IXGBE_ACI_PHY_EN_TX_LINK_PAUSE;
> +               pause_mask |= IXGBE_ACI_PHY_EN_RX_LINK_PAUSE;
> +               break;
> +       case ixgbe_fc_rx_pause:
> +               pause_mask |= IXGBE_ACI_PHY_EN_RX_LINK_PAUSE;
> +               break;
> +       case ixgbe_fc_tx_pause:
> +               pause_mask |= IXGBE_ACI_PHY_EN_TX_LINK_PAUSE;
> +               break;
> +       default:
> +               break;
> +       }
> +
> +       /* Clear the old pause settings. */
> +       cfg->caps &= ~(IXGBE_ACI_PHY_EN_TX_LINK_PAUSE |
> +               IXGBE_ACI_PHY_EN_RX_LINK_PAUSE);
> +
> +       /* Set the new capabilities. */
> +       cfg->caps |= pause_mask;
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_setup_fc_e610 - Set up flow control
> + * @hw: pointer to hardware structure
> + *
> + * Set up flow control. This has to be done during init time.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_setup_fc_e610(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_aci_cmd_get_phy_caps_data pcaps = { 0 };
> +       struct ixgbe_aci_cmd_set_phy_cfg_data cfg = { 0 };
> +       int err;
> +
> +       /* Get the current PHY config */
> +       err = ixgbe_aci_get_phy_caps(hw, false,
> +                                    IXGBE_ACI_REPORT_ACTIVE_CFG, &pcaps);
> +       if (err)
> +               return err;
> +
> +       ixgbe_copy_phy_caps_to_cfg(&pcaps, &cfg);
> +
> +       /* Configure the set PHY data */
> +       err = ixgbe_cfg_phy_fc(hw, &cfg, hw->fc.requested_mode);
> +       if (err)
> +               return err;
> +
> +       /* If the capabilities have changed, then set the new config */
> +       if (cfg.caps != pcaps.caps) {
> +               cfg.caps |= IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT;
> +
> +               err = ixgbe_aci_set_phy_cfg(hw, &cfg);
> +               if (err)
> +                       return err;
> +       }
> +
> +       return err;
> +}
> +
> +/**
> + * ixgbe_fc_autoneg_e610 - Configure flow control
> + * @hw: pointer to hardware structure
> + *
> + * Configure Flow Control.
> + */
> +void ixgbe_fc_autoneg_e610(struct ixgbe_hw *hw)
> +{
> +       int err;
> +
> +       /* Get current link err.
> +        * Current FC mode will be stored in the hw context.
> +        */
> +       err = ixgbe_aci_get_link_info(hw, false, NULL);
> +       if (err)
> +               goto no_autoneg;
> +
> +       /* Check if the link is up */
> +       if (!(hw->link.link_info.link_info & IXGBE_ACI_LINK_UP))
> +               goto no_autoneg;
> +
> +       /* Check if auto-negotiation has completed */
> +       if (!(hw->link.link_info.an_info & IXGBE_ACI_AN_COMPLETED))
> +               goto no_autoneg;
> +
> +       hw->fc.fc_was_autonegged = true;
> +       return;
> +
> +no_autoneg:
> +       hw->fc.fc_was_autonegged = false;
> +       hw->fc.current_mode = hw->fc.requested_mode;
> +}
> +
> +/**
> + * ixgbe_disable_rx_e610 - Disable RX unit
> + * @hw: pointer to hardware structure
> + *
> + * Disable RX DMA unit on E610 with use of ACI command (0x000C).
> + *
> + * Return: the exit code of the operation.
> + */
> +void ixgbe_disable_rx_e610(struct ixgbe_hw *hw)
> +{
> +       u32 rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
> +       u32 pfdtxgswc;
> +       int err;
> +
> +       if (!(rxctrl & IXGBE_RXCTRL_RXEN))
> +               return;
> +
> +       pfdtxgswc = IXGBE_READ_REG(hw, IXGBE_PFDTXGSWC);
> +       if (pfdtxgswc & IXGBE_PFDTXGSWC_VT_LBEN) {
> +               pfdtxgswc &= ~IXGBE_PFDTXGSWC_VT_LBEN;
> +               IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, pfdtxgswc);
> +               hw->mac.set_lben = true;
> +       } else {
> +               hw->mac.set_lben = false;
> +       }
> +
> +       err = ixgbe_aci_disable_rxen(hw);
> +
> +       /* If we fail - disable RX using register write */
> +       if (err) {
> +               rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
> +               if (rxctrl & IXGBE_RXCTRL_RXEN) {
> +                       rxctrl &= ~IXGBE_RXCTRL_RXEN;
> +                       IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl);
> +               }
> +       }
> +}
> +
> +/**
> + * ixgbe_init_phy_ops_e610 - PHY specific init
> + * @hw: pointer to hardware structure
> + *
> + * Initialize any function pointers that were not able to be
> + * set during init_shared_code because the PHY type was not known.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_init_phy_ops_e610(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_mac_info *mac = &hw->mac;
> +       struct ixgbe_phy_info *phy = &hw->phy;
> +       int ret_val;
> +
> +       if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper)
> +               phy->ops.set_phy_power = ixgbe_set_phy_power_e610;
> +       else
> +               phy->ops.set_phy_power = NULL;
> +
> +       /* Identify the PHY */
> +       ret_val = phy->ops.identify(hw);
[Kalesh] You can change it to:
return phy->ops.identify(hw);
> +       if (ret_val)
> +               return ret_val;
> +
> +       return ret_val;
> +}
> +
> +/**
> + * ixgbe_identify_phy_e610 - Identify PHY
> + * @hw: pointer to hardware structure
> + *
> + * Determine PHY type, supported speeds and PHY ID.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_identify_phy_e610(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_aci_cmd_get_phy_caps_data pcaps;
> +       int err;
> +
> +       /* Set PHY type */
> +       hw->phy.type = ixgbe_phy_fw;
> +
> +       err = ixgbe_aci_get_phy_caps(hw, false,
> +                                    IXGBE_ACI_REPORT_TOPO_CAP_MEDIA, &pcaps);
> +       if (err)
> +               return err;
> +
> +       if (!(pcaps.module_compliance_enforcement &
> +             IXGBE_ACI_MOD_ENFORCE_STRICT_MODE)) {
> +               /* Handle lenient mode */
> +               err = ixgbe_aci_get_phy_caps(hw, false,
> +                                            IXGBE_ACI_REPORT_TOPO_CAP_NO_MEDIA,
> +                                            &pcaps);
> +               if (err)
> +                       return err;
> +       }
> +
> +       /* Determine supported speeds */
> +       hw->phy.speeds_supported = IXGBE_LINK_SPEED_UNKNOWN;
> +
> +       if (pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_10BASE_T ||
> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_10M_SGMII)
> +               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_10_FULL;
> +       if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_100BASE_TX ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_100M_SGMII ||
> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_100M_USXGMII)
> +               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_100_FULL;
> +       if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_T  ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_SX ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_LX ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_KX ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1G_SGMII    ||
> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_1G_USXGMII)
> +               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_1GB_FULL;
> +       if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_T       ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10G_SFI_DA      ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_SR      ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_LR      ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_KR_CR1  ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10G_SFI_AOC_ACC ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10G_SFI_C2C     ||
> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_10G_USXGMII)
> +               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_10GB_FULL;
> +
> +       /* 2.5 and 5 Gbps link speeds must be excluded from the
> +        * auto-negotiation set used during driver initialization due to
> +        * compatibility issues with certain switches. Those issues do not
> +        * exist in case of E610 2.5G SKU device (0x57b1).
> +        */
> +       if (!hw->phy.autoneg_advertised &&
> +           hw->device_id != IXGBE_DEV_ID_E610_2_5G_T)
> +               hw->phy.autoneg_advertised = hw->phy.speeds_supported;//PK
> +
> +       if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_2500BASE_T   ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_2500BASE_X   ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_2500BASE_KX  ||
> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_2500M_SGMII ||
> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_2500M_USXGMII)
> +               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_2_5GB_FULL;
> +
> +       if (!hw->phy.autoneg_advertised &&
> +           hw->device_id == IXGBE_DEV_ID_E610_2_5G_T)
> +               hw->phy.autoneg_advertised = hw->phy.speeds_supported;//PK
> +
> +       if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_5GBASE_T  ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_5GBASE_KR ||
> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_5G_USXGMII)
> +               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_5GB_FULL;
> +
> +       /* Set PHY ID */
> +       memcpy(&hw->phy.id, pcaps.phy_id_oui, sizeof(u32));
> +
> +       hw->phy.eee_speeds_supported = IXGBE_LINK_SPEED_10_FULL |
> +                                      IXGBE_LINK_SPEED_100_FULL |
> +                                      IXGBE_LINK_SPEED_1GB_FULL;
> +       hw->phy.eee_speeds_advertised = hw->phy.eee_speeds_supported;
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_identify_module_e610 - Identify SFP module type
> + * @hw: pointer to hardware structure
> + *
> + * Identify the SFP module type.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_identify_module_e610(struct ixgbe_hw *hw)
> +{
> +       bool media_available;
> +       u8 module_type;
> +       int err;
> +
> +       err = ixgbe_update_link_info(hw);
> +       if (err)
> +               return err;
> +
> +       media_available =
> +               (hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE);
> +
> +       if (media_available) {
> +               hw->phy.sfp_type = ixgbe_sfp_type_unknown;
> +
> +               /* Get module type from hw context updated by
> +                * ixgbe_update_link_info()
> +                */
> +               module_type = hw->link.link_info.module_type[IXGBE_ACI_MOD_TYPE_IDENT];
> +
> +               if ((module_type & IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_PASSIVE) ||
> +                   (module_type & IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_ACTIVE)) {
> +                       hw->phy.sfp_type = ixgbe_sfp_type_da_cu;
> +               } else if (module_type & IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_SR) {
> +                       hw->phy.sfp_type = ixgbe_sfp_type_sr;
> +               } else if ((module_type & IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_LR) ||
> +                          (module_type & IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_LRM)) {
> +                       hw->phy.sfp_type = ixgbe_sfp_type_lr;
> +               }
> +       } else {
> +               hw->phy.sfp_type = ixgbe_sfp_type_not_present;
> +               return -ENOENT;
> +       }
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_setup_phy_link_e610 - Sets up firmware-controlled PHYs
> + * @hw: pointer to hardware structure
> + *
> + * Set the parameters for the firmware-controlled PHYs.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_setup_phy_link_e610(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_aci_cmd_get_phy_caps_data pcaps;
> +       struct ixgbe_aci_cmd_set_phy_cfg_data pcfg;
> +       u8 rmode = IXGBE_ACI_REPORT_TOPO_CAP_MEDIA;
> +       u64 sup_phy_type_low, sup_phy_type_high;
> +       int err;
> +
> +       err = ixgbe_aci_get_link_info(hw, false, NULL);
> +       if (err)
> +               return err;
> +
> +       /* If media is not available get default config. */
> +       if (!(hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE))
> +               rmode = IXGBE_ACI_REPORT_DFLT_CFG;
> +
> +       err = ixgbe_aci_get_phy_caps(hw, false, rmode, &pcaps);
> +       if (err)
> +               return err;
> +
> +       sup_phy_type_low = pcaps.phy_type_low;
> +       sup_phy_type_high = pcaps.phy_type_high;
> +
> +       /* Get Active configuration to avoid unintended changes. */
> +       err = ixgbe_aci_get_phy_caps(hw, false, IXGBE_ACI_REPORT_ACTIVE_CFG,
> +                                    &pcaps);
> +       if (err)
> +               return err;
> +
> +       ixgbe_copy_phy_caps_to_cfg(&pcaps, &pcfg);
> +
> +       /* Set default PHY types for a given speed */
> +       pcfg.phy_type_low = 0;
> +       pcfg.phy_type_high = 0;
> +
> +       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10_FULL) {
> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_10BASE_T;
> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_10M_SGMII;
> +       }
> +       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) {
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_100BASE_TX;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_100M_SGMII;
> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_100M_USXGMII;
> +       }
> +       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) {
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_T;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_SX;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_LX;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_KX;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1G_SGMII;
> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_1G_USXGMII;
> +       }
> +       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_2_5GB_FULL) {
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_2500BASE_T;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_2500BASE_X;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_2500BASE_KX;
> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_2500M_SGMII;
> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_2500M_USXGMII;
> +       }
> +       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_5GB_FULL) {
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_5GBASE_T;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_5GBASE_KR;
> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_5G_USXGMII;
> +       }
> +       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) {
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_T;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10G_SFI_DA;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_SR;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_LR;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_KR_CR1;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10G_SFI_AOC_ACC;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10G_SFI_C2C;
> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_10G_USXGMII;
> +       }
> +
> +       /* Mask the set values to avoid requesting unsupported link types */
> +       pcfg.phy_type_low &= sup_phy_type_low;
> +       pcfg.phy_type_high &= sup_phy_type_high;
> +
> +       if (pcfg.phy_type_high != pcaps.phy_type_high ||
> +           pcfg.phy_type_low != pcaps.phy_type_low ||
> +           pcfg.caps != pcaps.caps) {
> +               pcfg.caps |= IXGBE_ACI_PHY_ENA_LINK;
> +               pcfg.caps |= IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT;
> +
> +               err = ixgbe_aci_set_phy_cfg(hw, &pcfg);
> +               if (err)
> +                       return err;
> +       }
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_set_phy_power_e610 - Control power for copper PHY
> + * @hw: pointer to hardware structure
> + * @on: true for on, false for off
> + *
> + * Set the power on/off of the PHY
> + * by getting its capabilities and setting the appropriate
> + * configuration parameters.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_set_phy_power_e610(struct ixgbe_hw *hw, bool on)
> +{
> +       struct ixgbe_aci_cmd_get_phy_caps_data phy_caps = { 0 };
> +       struct ixgbe_aci_cmd_set_phy_cfg_data phy_cfg = { 0 };
> +       int err;
> +
> +       err = ixgbe_aci_get_phy_caps(hw, false,
> +                                    IXGBE_ACI_REPORT_ACTIVE_CFG,
> +                                    &phy_caps);
> +       if (err)
> +               return err;
> +
> +       ixgbe_copy_phy_caps_to_cfg(&phy_caps, &phy_cfg);
> +
> +       if (on)
> +               phy_cfg.caps &= ~IXGBE_ACI_PHY_ENA_LOW_POWER;
> +       else
> +               phy_cfg.caps |= IXGBE_ACI_PHY_ENA_LOW_POWER;
> +
> +       /* PHY is already in requested power mode. */
> +       if (phy_caps.caps == phy_cfg.caps)
> +               return 0;
> +
> +       phy_cfg.caps |= IXGBE_ACI_PHY_ENA_LINK;
> +       phy_cfg.caps |= IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT;
> +
> +       err = ixgbe_aci_set_phy_cfg(hw, &phy_cfg);
[Kalesh] Change it as:
return  ixgbe_aci_set_phy_cfg(hw, &phy_cfg);
> +
> +       return err;
> +}
> +
> +/**
> + * ixgbe_enter_lplu_e610 - Transition to low power states
> + * @hw: pointer to hardware structure
> + *
> + * Configures Low Power Link Up on transition to low power states
> + * (from D0 to non-D0). Link is required to enter LPLU so avoid resetting the
> + * X557 PHY immediately prior to entering LPLU.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_enter_lplu_e610(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_aci_cmd_get_phy_caps_data phy_caps = { 0 };
> +       struct ixgbe_aci_cmd_set_phy_cfg_data phy_cfg = { 0 };
> +       int err;
> +
> +       err = ixgbe_aci_get_phy_caps(hw, false,
> +                                    IXGBE_ACI_REPORT_ACTIVE_CFG,
> +                                    &phy_caps);
> +       if (err)
> +               return err;
> +
> +       ixgbe_copy_phy_caps_to_cfg(&phy_caps, &phy_cfg);
> +
> +       phy_cfg.low_power_ctrl_an |= IXGBE_ACI_PHY_EN_D3COLD_LOW_POWER_AUTONEG;
> +
> +       err = ixgbe_aci_set_phy_cfg(hw, &phy_cfg);
[Kalesh] Same comment as above
> +
> +       return err;
> +}
> +
> +/**
> + * ixgbe_aci_get_netlist_node - get a node handle
> + * @hw: pointer to the hw struct
> + * @cmd: get_link_topo AQ structure
> + * @node_part_number: output node part number if node found
> + * @node_handle: output node handle parameter if node found
> + *
> + * Get the netlist node and assigns it to
> + * the provided handle using ACI command (0x06E0).
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_aci_get_netlist_node(struct ixgbe_hw *hw,
> +                              struct ixgbe_aci_cmd_get_link_topo *cmd,
> +                              u8 *node_part_number, u16 *node_handle)
> +{
> +       struct ixgbe_aci_desc desc;
> +
> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_link_topo);
> +       desc.params.get_link_topo = *cmd;
> +
> +       if (ixgbe_aci_send_cmd(hw, &desc, NULL, 0))
> +               return -EOPNOTSUPP;
> +
> +       if (node_handle)
> +               *node_handle = desc.params.get_link_topo.addr.handle;
> +       if (node_part_number)
> +               *node_part_number = desc.params.get_link_topo.node_part_num;
> +
> +       return 0;
> +}
> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
> index 5c5a676..4a4f969 100644
> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
> @@ -27,5 +27,37 @@ int ixgbe_aci_get_phy_caps(struct ixgbe_hw *hw, bool qual_mods, u8 report_mode,
>                            struct ixgbe_aci_cmd_get_phy_caps_data *pcaps);
>  void ixgbe_copy_phy_caps_to_cfg(struct ixgbe_aci_cmd_get_phy_caps_data *caps,
>                                 struct ixgbe_aci_cmd_set_phy_cfg_data *cfg);
> +int ixgbe_aci_set_phy_cfg(struct ixgbe_hw *hw,
> +                         struct ixgbe_aci_cmd_set_phy_cfg_data *cfg);
> +int ixgbe_aci_set_link_restart_an(struct ixgbe_hw *hw, bool ena_link);
> +int ixgbe_update_link_info(struct ixgbe_hw *hw);
> +int ixgbe_get_link_status(struct ixgbe_hw *hw, bool *link_up);
> +int ixgbe_aci_get_link_info(struct ixgbe_hw *hw, bool ena_lse,
> +                           struct ixgbe_link_status *link);
> +int ixgbe_aci_set_event_mask(struct ixgbe_hw *hw, u8 port_num, u16 mask);
> +int ixgbe_configure_lse(struct ixgbe_hw *hw, bool activate, u16 mask);
> +enum ixgbe_media_type ixgbe_get_media_type_e610(struct ixgbe_hw *hw);
> +int ixgbe_setup_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed speed,
> +                         bool autoneg_wait);
> +int ixgbe_check_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
> +                         bool *link_up, bool link_up_wait_to_complete);
> +int ixgbe_get_link_capabilities_e610(struct ixgbe_hw *hw,
> +                                    ixgbe_link_speed *speed,
> +                                    bool *autoneg);
> +int ixgbe_cfg_phy_fc(struct ixgbe_hw *hw,
> +                    struct ixgbe_aci_cmd_set_phy_cfg_data *cfg,
> +                    enum ixgbe_fc_mode req_mode);
> +int ixgbe_setup_fc_e610(struct ixgbe_hw *hw);
> +void ixgbe_fc_autoneg_e610(struct ixgbe_hw *hw);
> +void ixgbe_disable_rx_e610(struct ixgbe_hw *hw);
> +int ixgbe_init_phy_ops_e610(struct ixgbe_hw *hw);
> +int ixgbe_identify_phy_e610(struct ixgbe_hw *hw);
> +int ixgbe_identify_module_e610(struct ixgbe_hw *hw);
> +int ixgbe_setup_phy_link_e610(struct ixgbe_hw *hw);
> +int ixgbe_set_phy_power_e610(struct ixgbe_hw *hw, bool on);
> +int ixgbe_enter_lplu_e610(struct ixgbe_hw *hw);
> +int ixgbe_aci_get_netlist_node(struct ixgbe_hw *hw,
> +                              struct ixgbe_aci_cmd_get_link_topo *cmd,
> +                              u8 *node_part_number, u16 *node_handle);
>
>  #endif /* _IXGBE_E610_H_ */
> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
> index 6c6d990..1f97652 100644
> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
> @@ -652,6 +652,7 @@ struct ixgbe_aci_cmd_link_topo_params {
>  #define IXGBE_ACI_LINK_TOPO_NODE_TYPE_CLK_MUX  10
>  #define IXGBE_ACI_LINK_TOPO_NODE_TYPE_GPS      11
>  #define IXGBE_ACI_LINK_TOPO_NODE_CTX_S         4
> +#define IXGBE_ACI_LINK_TOPO_NODE_CTX_M         GENMASK(7, 4)
>  #define IXGBE_ACI_LINK_TOPO_NODE_CTX_GLOBAL                    0
>  #define IXGBE_ACI_LINK_TOPO_NODE_CTX_BOARD                     1
>  #define IXGBE_ACI_LINK_TOPO_NODE_CTX_PORT                      2
> --
> 2.43.0
>
>


-- 
Regards,
Kalesh A P

[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4239 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH iwl-next v9 2/7] ixgbe: Add support for E610 device capabilities detection
  2024-10-03 14:16 ` [PATCH iwl-next v9 2/7] ixgbe: Add support for E610 device capabilities detection Piotr Kwapulinski
  2024-10-17  9:46   ` Simon Horman
@ 2024-10-18  3:06   ` Kalesh Anakkur Purayil
  2024-10-21  8:42     ` Kwapulinski, Piotr
  2024-10-23 12:27     ` Kwapulinski, Piotr
  1 sibling, 2 replies; 16+ messages in thread
From: Kalesh Anakkur Purayil @ 2024-10-18  3:06 UTC (permalink / raw)
  To: Piotr Kwapulinski
  Cc: intel-wired-lan, netdev, Stefan Wegrzyn, Jedrzej Jagielski,
	Jan Sokolowski

[-- Attachment #1: Type: text/plain, Size: 24673 bytes --]

On Thu, Oct 3, 2024 at 7:48 PM Piotr Kwapulinski
<piotr.kwapulinski@intel.com> wrote:
>
> Add low level support for E610 device capabilities detection. The
> capabilities are discovered via the Admin Command Interface. Discover the
> following capabilities:
> - function caps: vmdq, dcb, rss, rx/tx qs, msix, nvm, orom, reset
> - device caps: vsi, fdir, 1588
> - phy caps
>
> Co-developed-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
> Signed-off-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
> Co-developed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
> Signed-off-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
> Reviewed-by: Jan Sokolowski <jan.sokolowski@intel.com>
> Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>

Hi Piotr,

Some minor cosmetic comments in line.

> ---
>  drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 540 ++++++++++++++++++
>  drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h |  12 +
>  drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |   8 +
>  3 files changed, 560 insertions(+)
>
> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
> index 28bd7da..3bc88df 100644
> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
> @@ -493,3 +493,543 @@ void ixgbe_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res)
>                 total_delay++;
>         }
>  }
> +
> +/**
> + * ixgbe_parse_e610_caps - Parse common device/function capabilities
> + * @hw: pointer to the HW struct
> + * @caps: pointer to common capabilities structure
> + * @elem: the capability element to parse
> + * @prefix: message prefix for tracing capabilities
> + *
> + * Given a capability element, extract relevant details into the common
> + * capability structure.
> + *
> + * Return: true if the capability matches one of the common capability ids,
> + * false otherwise.
> + */
> +static bool ixgbe_parse_e610_caps(struct ixgbe_hw *hw,
> +                                 struct ixgbe_hw_caps *caps,
> +                                 struct ixgbe_aci_cmd_list_caps_elem *elem,
> +                                 const char *prefix)
> +{
> +       u32 logical_id = elem->logical_id;
> +       u32 phys_id = elem->phys_id;
> +       u32 number = elem->number;
> +       u16 cap = elem->cap;
> +
> +       switch (cap) {
> +       case IXGBE_ACI_CAPS_VALID_FUNCTIONS:
> +               caps->valid_functions = number;
> +               break;
> +       case IXGBE_ACI_CAPS_SRIOV:
> +               caps->sr_iov_1_1 = (number == 1);
> +               break;
> +       case IXGBE_ACI_CAPS_VMDQ:
> +               caps->vmdq = (number == 1);
> +               break;
> +       case IXGBE_ACI_CAPS_DCB:
> +               caps->dcb = (number == 1);
> +               caps->active_tc_bitmap = logical_id;
> +               caps->maxtc = phys_id;
> +               break;
> +       case IXGBE_ACI_CAPS_RSS:
> +               caps->rss_table_size = number;
> +               caps->rss_table_entry_width = logical_id;
> +               break;
> +       case IXGBE_ACI_CAPS_RXQS:
> +               caps->num_rxq = number;
> +               caps->rxq_first_id = phys_id;
> +               break;
> +       case IXGBE_ACI_CAPS_TXQS:
> +               caps->num_txq = number;
> +               caps->txq_first_id = phys_id;
> +               break;
> +       case IXGBE_ACI_CAPS_MSIX:
> +               caps->num_msix_vectors = number;
> +               caps->msix_vector_first_id = phys_id;
> +               break;
> +       case IXGBE_ACI_CAPS_NVM_VER:
> +               break;
> +       case IXGBE_ACI_CAPS_MAX_MTU:
> +               caps->max_mtu = number;
> +               break;
> +       case IXGBE_ACI_CAPS_PCIE_RESET_AVOIDANCE:
> +               caps->pcie_reset_avoidance = (number > 0);
> +               break;
> +       case IXGBE_ACI_CAPS_POST_UPDATE_RESET_RESTRICT:
> +               caps->reset_restrict_support = (number == 1);
> +               break;
> +       case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG0:
> +       case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG1:
> +       case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG2:
> +       case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG3:
> +       {
> +               u8 index = cap - IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG0;
> +
> +               caps->ext_topo_dev_img_ver_high[index] = number;
> +               caps->ext_topo_dev_img_ver_low[index] = logical_id;
> +               caps->ext_topo_dev_img_part_num[index] =
> +                       FIELD_GET(IXGBE_EXT_TOPO_DEV_IMG_PART_NUM_M, phys_id);
> +               caps->ext_topo_dev_img_load_en[index] =
> +                       (phys_id & IXGBE_EXT_TOPO_DEV_IMG_LOAD_EN) != 0;
> +               caps->ext_topo_dev_img_prog_en[index] =
> +                       (phys_id & IXGBE_EXT_TOPO_DEV_IMG_PROG_EN) != 0;
> +               break;
> +       }
> +       default:
> +               /* Not one of the recognized common capabilities */
> +               return false;
> +       }
> +
> +       return true;
> +}
> +
> +/**
> + * ixgbe_parse_valid_functions_cap - Parse IXGBE_ACI_CAPS_VALID_FUNCTIONS caps
> + * @hw: pointer to the HW struct
> + * @dev_p: pointer to device capabilities structure
> + * @cap: capability element to parse
> + *
> + * Parse IXGBE_ACI_CAPS_VALID_FUNCTIONS for device capabilities.
> + */
> +static void
> +ixgbe_parse_valid_functions_cap(struct ixgbe_hw *hw,
> +                               struct ixgbe_hw_dev_caps *dev_p,
> +                               struct ixgbe_aci_cmd_list_caps_elem *cap)
> +{
> +       u32 number = cap->number;
[Kalesh] Do you really need a local variable here? Same comment
applies to functions below as well.
> +
> +       dev_p->num_funcs = hweight32(number);
> +}
> +
> +/**
> + * ixgbe_parse_vf_dev_caps - Parse IXGBE_ACI_CAPS_VF device caps
> + * @hw: pointer to the HW struct
> + * @dev_p: pointer to device capabilities structure
> + * @cap: capability element to parse
> + *
> + * Parse IXGBE_ACI_CAPS_VF for device capabilities.
> + */
> +static void ixgbe_parse_vf_dev_caps(struct ixgbe_hw *hw,
> +                                   struct ixgbe_hw_dev_caps *dev_p,
> +                                   struct ixgbe_aci_cmd_list_caps_elem *cap)
> +{
> +       u32 number = cap->number;
> +
> +       dev_p->num_vfs_exposed = number;
> +}
> +
> +/**
> + * ixgbe_parse_vsi_dev_caps - Parse IXGBE_ACI_CAPS_VSI device caps
> + * @hw: pointer to the HW struct
> + * @dev_p: pointer to device capabilities structure
> + * @cap: capability element to parse
> + *
> + * Parse IXGBE_ACI_CAPS_VSI for device capabilities.
> + */
> +static void ixgbe_parse_vsi_dev_caps(struct ixgbe_hw *hw,
> +                                    struct ixgbe_hw_dev_caps *dev_p,
> +                                    struct ixgbe_aci_cmd_list_caps_elem *cap)
> +{
> +       u32 number = cap->number;
> +
> +       dev_p->num_vsi_allocd_to_host = number;
> +}
> +
> +/**
> + * ixgbe_parse_fdir_dev_caps - Parse IXGBE_ACI_CAPS_FD device caps
> + * @hw: pointer to the HW struct
> + * @dev_p: pointer to device capabilities structure
> + * @cap: capability element to parse
> + *
> + * Parse IXGBE_ACI_CAPS_FD for device capabilities.
> + */
> +static void ixgbe_parse_fdir_dev_caps(struct ixgbe_hw *hw,
> +                                     struct ixgbe_hw_dev_caps *dev_p,
> +                                     struct ixgbe_aci_cmd_list_caps_elem *cap)
> +{
> +       u32 number = cap->number;
> +
> +       dev_p->num_flow_director_fltr = number;
> +}
> +
> +/**
> + * ixgbe_parse_dev_caps - Parse device capabilities
> + * @hw: pointer to the HW struct
> + * @dev_p: pointer to device capabilities structure
> + * @buf: buffer containing the device capability records
> + * @cap_count: the number of capabilities
> + *
> + * Helper device to parse device (0x000B) capabilities list. For
> + * capabilities shared between device and function, this relies on
> + * ixgbe_parse_e610_caps.
> + *
> + * Loop through the list of provided capabilities and extract the relevant
> + * data into the device capabilities structured.
> + */
> +static void ixgbe_parse_dev_caps(struct ixgbe_hw *hw,
> +                                struct ixgbe_hw_dev_caps *dev_p,
> +                                void *buf, u32 cap_count)
> +{
> +       struct ixgbe_aci_cmd_list_caps_elem *cap_resp;
> +       u32 i;
> +
> +       cap_resp = (struct ixgbe_aci_cmd_list_caps_elem *)buf;
> +
> +       memset(dev_p, 0, sizeof(*dev_p));
> +
> +       for (i = 0; i < cap_count; i++) {
> +               u16 cap = cap_resp[i].cap;
> +
> +               ixgbe_parse_e610_caps(hw, &dev_p->common_cap, &cap_resp[i],
> +                                     "dev caps");
> +
> +               switch (cap) {
> +               case IXGBE_ACI_CAPS_VALID_FUNCTIONS:
> +                       ixgbe_parse_valid_functions_cap(hw, dev_p,
> +                                                       &cap_resp[i]);
> +                       break;
> +               case IXGBE_ACI_CAPS_VF:
> +                       ixgbe_parse_vf_dev_caps(hw, dev_p, &cap_resp[i]);
> +                       break;
> +               case IXGBE_ACI_CAPS_VSI:
> +                       ixgbe_parse_vsi_dev_caps(hw, dev_p, &cap_resp[i]);
> +                       break;
> +               case  IXGBE_ACI_CAPS_FD:
> +                       ixgbe_parse_fdir_dev_caps(hw, dev_p, &cap_resp[i]);
> +                       break;
> +               default:
> +                       /* Don't list common capabilities as unknown */
> +                       break;
> +               }
> +       }
> +}
> +
> +/**
> + * ixgbe_parse_vf_func_caps - Parse IXGBE_ACI_CAPS_VF function caps
> + * @hw: pointer to the HW struct
> + * @func_p: pointer to function capabilities structure
> + * @cap: pointer to the capability element to parse
> + *
> + * Extract function capabilities for IXGBE_ACI_CAPS_VF.
> + */
> +static void ixgbe_parse_vf_func_caps(struct ixgbe_hw *hw,
> +                                    struct ixgbe_hw_func_caps *func_p,
> +                                    struct ixgbe_aci_cmd_list_caps_elem *cap)
> +{
> +       u32 logical_id = cap->logical_id;
> +       u32 number = cap->number;
> +
> +       func_p->num_allocd_vfs = number;
> +       func_p->vf_base_id = logical_id;
> +}
> +
> +/**
> + * ixgbe_get_num_per_func - determine number of resources per PF
> + * @hw: pointer to the HW structure
> + * @max: value to be evenly split between each PF
> + *
> + * Determine the number of valid functions by going through the bitmap returned
> + * from parsing capabilities and use this to calculate the number of resources
> + * per PF based on the max value passed in.
> + *
> + * Return: the number of resources per PF or 0, if no PH are available.
> + */
> +static u32 ixgbe_get_num_per_func(struct ixgbe_hw *hw, u32 max)
> +{
> +#define IXGBE_CAPS_VALID_FUNCS_M       GENMASK(7, 0)
> +       u8 funcs = hweight8(hw->dev_caps.common_cap.valid_functions &
> +                           IXGBE_CAPS_VALID_FUNCS_M);
> +
> +       return funcs ? (max / funcs) : 0;
> +}
> +
> +/**
> + * ixgbe_parse_vsi_func_caps - Parse IXGBE_ACI_CAPS_VSI function caps
> + * @hw: pointer to the HW struct
> + * @func_p: pointer to function capabilities structure
> + * @cap: pointer to the capability element to parse
> + *
> + * Extract function capabilities for IXGBE_ACI_CAPS_VSI.
> + */
> +static void ixgbe_parse_vsi_func_caps(struct ixgbe_hw *hw,
> +                                     struct ixgbe_hw_func_caps *func_p,
> +                                     struct ixgbe_aci_cmd_list_caps_elem *cap)
> +{
> +       func_p->guar_num_vsi = ixgbe_get_num_per_func(hw, IXGBE_MAX_VSI);
> +}
> +
> +/**
> + * ixgbe_parse_func_caps - Parse function capabilities
> + * @hw: pointer to the HW struct
> + * @func_p: pointer to function capabilities structure
> + * @buf: buffer containing the function capability records
> + * @cap_count: the number of capabilities
> + *
> + * Helper function to parse function (0x000A) capabilities list. For
> + * capabilities shared between device and function, this relies on
> + * ixgbe_parse_e610_caps.
> + *
> + * Loop through the list of provided capabilities and extract the relevant
> + * data into the function capabilities structured.
> + */
> +static void ixgbe_parse_func_caps(struct ixgbe_hw *hw,
> +                                 struct ixgbe_hw_func_caps *func_p,
> +                                 void *buf, u32 cap_count)
> +{
> +       struct ixgbe_aci_cmd_list_caps_elem *cap_resp;
> +       u32 i;
> +
> +       cap_resp = (struct ixgbe_aci_cmd_list_caps_elem *)buf;
> +
> +       memset(func_p, 0, sizeof(*func_p));
> +
> +       for (i = 0; i < cap_count; i++) {
> +               u16 cap = cap_resp[i].cap;
> +
> +               ixgbe_parse_e610_caps(hw, &func_p->common_cap,
> +                                     &cap_resp[i], "func caps");
> +
> +               switch (cap) {
> +               case IXGBE_ACI_CAPS_VF:
> +                       ixgbe_parse_vf_func_caps(hw, func_p, &cap_resp[i]);
> +                       break;
> +               case IXGBE_ACI_CAPS_VSI:
> +                       ixgbe_parse_vsi_func_caps(hw, func_p, &cap_resp[i]);
> +                       break;
> +               default:
> +                       /* Don't list common capabilities as unknown */
> +                       break;
> +               }
> +       }
> +}
> +
> +/**
> + * ixgbe_aci_list_caps - query function/device capabilities
> + * @hw: pointer to the HW struct
> + * @buf: a buffer to hold the capabilities
> + * @buf_size: size of the buffer
> + * @cap_count: if not NULL, set to the number of capabilities reported
> + * @opc: capabilities type to discover, device or function
> + *
> + * Get the function (0x000A) or device (0x000B) capabilities description from
> + * firmware and store it in the buffer.
> + *
> + * If the cap_count pointer is not NULL, then it is set to the number of
> + * capabilities firmware will report. Note that if the buffer size is too
> + * small, it is possible the command will return -ENOMEM. The
> + * cap_count will still be updated in this case. It is recommended that the
> + * buffer size be set to IXGBE_ACI_MAX_BUFFER_SIZE (the largest possible
> + * buffer that firmware could return) to avoid this.
> + *
> + * Return: the exit code of the operation.
> + * Exit code of -ENOMEM means the buffer size is too small.
> + */
> +int ixgbe_aci_list_caps(struct ixgbe_hw *hw, void *buf, u16 buf_size,
> +                       u32 *cap_count, enum ixgbe_aci_opc opc)
> +{
> +       struct ixgbe_aci_cmd_list_caps *cmd;
> +       struct ixgbe_aci_desc desc;
> +       int err;
> +
> +       cmd = &desc.params.get_cap;
> +
> +       if (opc != ixgbe_aci_opc_list_func_caps &&
> +           opc != ixgbe_aci_opc_list_dev_caps)
> +               return -EINVAL;
> +
> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, opc);
> +       err = ixgbe_aci_send_cmd(hw, &desc, buf, buf_size);
> +
> +       if (cap_count)
[Kalesh] Do you need a check for !err as well here?
> +               *cap_count = cmd->count;
> +
> +       return err;
> +}
> +
> +/**
> + * ixgbe_discover_dev_caps - Read and extract device capabilities
> + * @hw: pointer to the hardware structure
> + * @dev_caps: pointer to device capabilities structure
> + *
> + * Read the device capabilities and extract them into the dev_caps structure
> + * for later use.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_discover_dev_caps(struct ixgbe_hw *hw,
> +                           struct ixgbe_hw_dev_caps *dev_caps)
> +{
> +       u8 *cbuf __free(kfree);
> +       u32 cap_count;
> +       int err;
> +
> +       cbuf = kzalloc(IXGBE_ACI_MAX_BUFFER_SIZE, GFP_KERNEL);
> +       if (!cbuf)
> +               return -ENOMEM;
> +       /* Although the driver doesn't know the number of capabilities the
> +        * device will return, we can simply send a 4KB buffer, the maximum
> +        * possible size that firmware can return.
> +        */
> +       cap_count = IXGBE_ACI_MAX_BUFFER_SIZE /
> +                   sizeof(struct ixgbe_aci_cmd_list_caps_elem);
> +
> +       err = ixgbe_aci_list_caps(hw, cbuf, IXGBE_ACI_MAX_BUFFER_SIZE,
> +                                 &cap_count,
> +                                 ixgbe_aci_opc_list_dev_caps);
> +       if (err)
> +               return err;
> +
> +       ixgbe_parse_dev_caps(hw, dev_caps, cbuf, cap_count);
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_discover_func_caps - Read and extract function capabilities
> + * @hw: pointer to the hardware structure
> + * @func_caps: pointer to function capabilities structure
> + *
> + * Read the function capabilities and extract them into the func_caps structure
> + * for later use.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_discover_func_caps(struct ixgbe_hw *hw,
> +                            struct ixgbe_hw_func_caps *func_caps)
> +{
> +       u8 *cbuf __free(kfree);
> +       u32 cap_count;
> +       int err;
> +
> +       cbuf = kzalloc(IXGBE_ACI_MAX_BUFFER_SIZE, GFP_KERNEL);
> +       if (!cbuf)
> +               return -ENOMEM;
> +
> +       /* Although the driver doesn't know the number of capabilities the
> +        * device will return, we can simply send a 4KB buffer, the maximum
> +        * possible size that firmware can return.
> +        */
> +       cap_count = IXGBE_ACI_MAX_BUFFER_SIZE /
> +                   sizeof(struct ixgbe_aci_cmd_list_caps_elem);
> +
> +       err = ixgbe_aci_list_caps(hw, cbuf, IXGBE_ACI_MAX_BUFFER_SIZE,
> +                                 &cap_count,
> +                                 ixgbe_aci_opc_list_func_caps);
> +       if (err)
> +               return err;
> +
> +       ixgbe_parse_func_caps(hw, func_caps, cbuf, cap_count);
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_get_caps - get info about the HW
> + * @hw: pointer to the hardware structure
> + *
> + * Retrieve both device and function capabilities.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_get_caps(struct ixgbe_hw *hw)
> +{
> +       int err;
> +
> +       err = ixgbe_discover_dev_caps(hw, &hw->dev_caps);
> +       if (err)
> +               return err;
> +
> +       return ixgbe_discover_func_caps(hw, &hw->func_caps);
> +}
> +
> +/**
> + * ixgbe_aci_disable_rxen - disable RX
> + * @hw: pointer to the HW struct
> + *
> + * Request a safe disable of Receive Enable using ACI command (0x000C).
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_aci_disable_rxen(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_aci_cmd_disable_rxen *cmd;
> +       struct ixgbe_aci_desc desc;
> +
> +       cmd = &desc.params.disable_rxen;
> +
> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_disable_rxen);
> +
> +       cmd->lport_num = hw->bus.func;
> +
> +       return ixgbe_aci_send_cmd(hw, &desc, NULL, 0);
> +}
> +
> +/**
> + * ixgbe_aci_get_phy_caps - returns PHY capabilities
> + * @hw: pointer to the HW struct
> + * @qual_mods: report qualified modules
> + * @report_mode: report mode capabilities
> + * @pcaps: structure for PHY capabilities to be filled
> + *
> + * Returns the various PHY capabilities supported on the Port
> + * using ACI command (0x0600).
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_aci_get_phy_caps(struct ixgbe_hw *hw, bool qual_mods, u8 report_mode,
> +                          struct ixgbe_aci_cmd_get_phy_caps_data *pcaps)
> +{
> +       struct ixgbe_aci_cmd_get_phy_caps *cmd;
> +       u16 pcaps_size = sizeof(*pcaps);
> +       struct ixgbe_aci_desc desc;
> +       int err;
> +
> +       cmd = &desc.params.get_phy;
> +
> +       if (!pcaps || (report_mode & ~IXGBE_ACI_REPORT_MODE_M))
> +               return -EINVAL;
> +
> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_phy_caps);
> +
> +       if (qual_mods)
> +               cmd->param0 |= IXGBE_ACI_GET_PHY_RQM;
> +
> +       cmd->param0 |= report_mode;
> +       err = ixgbe_aci_send_cmd(hw, &desc, pcaps, pcaps_size);
> +
> +       if (!err && report_mode == IXGBE_ACI_REPORT_TOPO_CAP_MEDIA) {
> +               hw->phy.phy_type_low = pcaps->phy_type_low;
> +               hw->phy.phy_type_high = pcaps->phy_type_high;
> +               memcpy(hw->link.link_info.module_type, &pcaps->module_type,
> +                      sizeof(hw->link.link_info.module_type));
> +       }
> +
> +       return err;
> +}
> +
> +/**
> + * ixgbe_copy_phy_caps_to_cfg - Copy PHY ability data to configuration data
> + * @caps: PHY ability structure to copy data from
> + * @cfg: PHY configuration structure to copy data to
> + *
> + * Helper function to copy data from PHY capabilities data structure
> + * to PHY configuration data structure
> + */
> +void ixgbe_copy_phy_caps_to_cfg(struct ixgbe_aci_cmd_get_phy_caps_data *caps,
> +                               struct ixgbe_aci_cmd_set_phy_cfg_data *cfg)
> +{
> +       if (!caps || !cfg)
> +               return;
> +
> +       memset(cfg, 0, sizeof(*cfg));
> +       cfg->phy_type_low = caps->phy_type_low;
> +       cfg->phy_type_high = caps->phy_type_high;
> +       cfg->caps = caps->caps;
> +       cfg->low_power_ctrl_an = caps->low_power_ctrl_an;
> +       cfg->eee_cap = caps->eee_cap;
> +       cfg->eeer_value = caps->eeer_value;
> +       cfg->link_fec_opt = caps->link_fec_options;
> +       cfg->module_compliance_enforcement =
> +               caps->module_compliance_enforcement;
> +}
> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
> index 18b831b..5c5a676 100644
> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
> @@ -15,5 +15,17 @@ void ixgbe_fill_dflt_direct_cmd_desc(struct ixgbe_aci_desc *desc, u16 opcode);
>  int ixgbe_acquire_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res,
>                       enum ixgbe_aci_res_access_type access, u32 timeout);
>  void ixgbe_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res);
> +int ixgbe_aci_list_caps(struct ixgbe_hw *hw, void *buf, u16 buf_size,
> +                       u32 *cap_count, enum ixgbe_aci_opc opc);
> +int ixgbe_discover_dev_caps(struct ixgbe_hw *hw,
> +                           struct ixgbe_hw_dev_caps *dev_caps);
> +int ixgbe_discover_func_caps(struct ixgbe_hw *hw,
> +                            struct ixgbe_hw_func_caps *func_caps);
> +int ixgbe_get_caps(struct ixgbe_hw *hw);
> +int ixgbe_aci_disable_rxen(struct ixgbe_hw *hw);
> +int ixgbe_aci_get_phy_caps(struct ixgbe_hw *hw, bool qual_mods, u8 report_mode,
> +                          struct ixgbe_aci_cmd_get_phy_caps_data *pcaps);
> +void ixgbe_copy_phy_caps_to_cfg(struct ixgbe_aci_cmd_get_phy_caps_data *caps,
> +                               struct ixgbe_aci_cmd_set_phy_cfg_data *cfg);
>
>  #endif /* _IXGBE_E610_H_ */
> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> index 8b8404d..0302a21 100644
> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> @@ -43,6 +43,7 @@
>  #include "ixgbe.h"
>  #include "ixgbe_common.h"
>  #include "ixgbe_dcb_82599.h"
> +#include "ixgbe_e610.h"
>  #include "ixgbe_phy.h"
>  #include "ixgbe_sriov.h"
>  #include "ixgbe_model.h"
> @@ -10932,6 +10933,13 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>         if (err)
>                 goto err_sw_init;
>
> +       if (adapter->hw.mac.type == ixgbe_mac_e610) {
> +               err = ixgbe_get_caps(&adapter->hw);
> +               if (err)
> +                       dev_err(&pdev->dev,
> +                               "ixgbe_get_caps failed %d\n", err);
[Kalesh] You can fit this log in one line
> +       }
> +
>         if (adapter->hw.mac.type == ixgbe_mac_82599EB)
>                 adapter->flags2 |= IXGBE_FLAG2_AUTO_DISABLE_VF;
>
> --
> 2.43.0
>
>


-- 
Regards,
Kalesh A P

[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4239 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: [PATCH iwl-next v9 2/7] ixgbe: Add support for E610 device capabilities detection
  2024-10-18  3:06   ` Kalesh Anakkur Purayil
@ 2024-10-21  8:42     ` Kwapulinski, Piotr
  2024-10-23 12:27     ` Kwapulinski, Piotr
  1 sibling, 0 replies; 16+ messages in thread
From: Kwapulinski, Piotr @ 2024-10-21  8:42 UTC (permalink / raw)
  To: Kalesh Anakkur Purayil
  Cc: intel-wired-lan@lists.osuosl.org, netdev@vger.kernel.org,
	Wegrzyn, Stefan, Jagielski, Jedrzej, Sokolowski, Jan

>-----Original Message-----
>From: Kalesh Anakkur Purayil <kalesh-anakkur.purayil@broadcom.com> 
>Sent: Friday, October 18, 2024 5:06 AM
>To: Kwapulinski, Piotr <piotr.kwapulinski@intel.com>
>Cc: intel-wired-lan@lists.osuosl.org; netdev@vger.kernel.org; Wegrzyn, Stefan <stefan.wegrzyn@intel.com>; Jagielski, Jedrzej <jedrzej.jagielski@intel.com>; Sokolowski, Jan <jan.sokolowski@intel.com>
>Subject: Re: [PATCH iwl-next v9 2/7] ixgbe: Add support for E610 device capabilities detection
>
>On Thu, Oct 3, 2024 at 7:48 PM Piotr Kwapulinski
><piotr.kwapulinski@intel.com> wrote:
>>
>> Add low level support for E610 device capabilities detection. The
>> capabilities are discovered via the Admin Command Interface. Discover the
>> following capabilities:
>> - function caps: vmdq, dcb, rss, rx/tx qs, msix, nvm, orom, reset
>> - device caps: vsi, fdir, 1588
>> - phy caps
>>
>> Co-developed-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
>> Signed-off-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
>> Co-developed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
>> Signed-off-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
>> Reviewed-by: Jan Sokolowski <jan.sokolowski@intel.com>
>> Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>
>
>Hi Piotr,
>
>Some minor cosmetic comments in line.
Hi Kalesh,
I'll update.
Thank you for review.
Piotr

>
>> ---
>>  drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 540 ++++++++++++++++++
>>  drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h |  12 +
>>  drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |   8 +
>>  3 files changed, 560 insertions(+)
>>
>> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
>> index 28bd7da..3bc88df 100644
>> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
>> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
>> @@ -493,3 +493,543 @@ void ixgbe_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res)
>>                 total_delay++;
>>         }
>>  }
>> +
>> +/**
>> + * ixgbe_parse_e610_caps - Parse common device/function capabilities
>> + * @hw: pointer to the HW struct
>> + * @caps: pointer to common capabilities structure
>> + * @elem: the capability element to parse
>> + * @prefix: message prefix for tracing capabilities
>> + *
>> + * Given a capability element, extract relevant details into the common
>> + * capability structure.
>> + *
>> + * Return: true if the capability matches one of the common capability ids,
>> + * false otherwise.
>> + */
>> +static bool ixgbe_parse_e610_caps(struct ixgbe_hw *hw,
>> +                                 struct ixgbe_hw_caps *caps,
>> +                                 struct ixgbe_aci_cmd_list_caps_elem *elem,
>> +                                 const char *prefix)
>> +{
>> +       u32 logical_id = elem->logical_id;
>> +       u32 phys_id = elem->phys_id;
>> +       u32 number = elem->number;
>> +       u16 cap = elem->cap;
>> +
>> +       switch (cap) {
>> +       case IXGBE_ACI_CAPS_VALID_FUNCTIONS:
>> +               caps->valid_functions = number;
>> +               break;
>> +       case IXGBE_ACI_CAPS_SRIOV:
>> +               caps->sr_iov_1_1 = (number == 1);
>> +               break;
>> +       case IXGBE_ACI_CAPS_VMDQ:
>> +               caps->vmdq = (number == 1);
>> +               break;
>> +       case IXGBE_ACI_CAPS_DCB:
>> +               caps->dcb = (number == 1);
>> +               caps->active_tc_bitmap = logical_id;
>> +               caps->maxtc = phys_id;
>> +               break;
>> +       case IXGBE_ACI_CAPS_RSS:
>> +               caps->rss_table_size = number;
>> +               caps->rss_table_entry_width = logical_id;
>> +               break;
>> +       case IXGBE_ACI_CAPS_RXQS:
>> +               caps->num_rxq = number;
>> +               caps->rxq_first_id = phys_id;
>> +               break;
>> +       case IXGBE_ACI_CAPS_TXQS:
>> +               caps->num_txq = number;
>> +               caps->txq_first_id = phys_id;
>> +               break;
>> +       case IXGBE_ACI_CAPS_MSIX:
>> +               caps->num_msix_vectors = number;
>> +               caps->msix_vector_first_id = phys_id;
>> +               break;
>> +       case IXGBE_ACI_CAPS_NVM_VER:
>> +               break;
>> +       case IXGBE_ACI_CAPS_MAX_MTU:
>> +               caps->max_mtu = number;
>> +               break;
>> +       case IXGBE_ACI_CAPS_PCIE_RESET_AVOIDANCE:
>> +               caps->pcie_reset_avoidance = (number > 0);
>> +               break;
>> +       case IXGBE_ACI_CAPS_POST_UPDATE_RESET_RESTRICT:
>> +               caps->reset_restrict_support = (number == 1);
>> +               break;
>> +       case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG0:
>> +       case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG1:
>> +       case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG2:
>> +       case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG3:
>> +       {
>> +               u8 index = cap - IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG0;
>> +
>> +               caps->ext_topo_dev_img_ver_high[index] = number;
>> +               caps->ext_topo_dev_img_ver_low[index] = logical_id;
>> +               caps->ext_topo_dev_img_part_num[index] =
>> +                       FIELD_GET(IXGBE_EXT_TOPO_DEV_IMG_PART_NUM_M, phys_id);
>> +               caps->ext_topo_dev_img_load_en[index] =
>> +                       (phys_id & IXGBE_EXT_TOPO_DEV_IMG_LOAD_EN) != 0;
>> +               caps->ext_topo_dev_img_prog_en[index] =
>> +                       (phys_id & IXGBE_EXT_TOPO_DEV_IMG_PROG_EN) != 0;
>> +               break;
>> +       }
>> +       default:
>> +               /* Not one of the recognized common capabilities */
>> +               return false;
>> +       }
>> +
>> +       return true;
>> +}
>> +
>> +/**
>> + * ixgbe_parse_valid_functions_cap - Parse IXGBE_ACI_CAPS_VALID_FUNCTIONS caps
>> + * @hw: pointer to the HW struct
>> + * @dev_p: pointer to device capabilities structure
>> + * @cap: capability element to parse
>> + *
>> + * Parse IXGBE_ACI_CAPS_VALID_FUNCTIONS for device capabilities.
>> + */
>> +static void
>> +ixgbe_parse_valid_functions_cap(struct ixgbe_hw *hw,
>> +                               struct ixgbe_hw_dev_caps *dev_p,
>> +                               struct ixgbe_aci_cmd_list_caps_elem *cap)
>> +{
>> +       u32 number = cap->number;
>[Kalesh] Do you really need a local variable here? Same comment
>applies to functions below as well.
>> +
>> +       dev_p->num_funcs = hweight32(number);
>> +}
>> +
>> +/**
>> + * ixgbe_parse_vf_dev_caps - Parse IXGBE_ACI_CAPS_VF device caps
>> + * @hw: pointer to the HW struct
>> + * @dev_p: pointer to device capabilities structure
>> + * @cap: capability element to parse
>> + *
>> + * Parse IXGBE_ACI_CAPS_VF for device capabilities.
>> + */
>> +static void ixgbe_parse_vf_dev_caps(struct ixgbe_hw *hw,
>> +                                   struct ixgbe_hw_dev_caps *dev_p,
>> +                                   struct ixgbe_aci_cmd_list_caps_elem *cap)
>> +{
>> +       u32 number = cap->number;
>> +
>> +       dev_p->num_vfs_exposed = number;
>> +}
>> +
>> +/**
>> + * ixgbe_parse_vsi_dev_caps - Parse IXGBE_ACI_CAPS_VSI device caps
>> + * @hw: pointer to the HW struct
>> + * @dev_p: pointer to device capabilities structure
>> + * @cap: capability element to parse
>> + *
>> + * Parse IXGBE_ACI_CAPS_VSI for device capabilities.
>> + */
>> +static void ixgbe_parse_vsi_dev_caps(struct ixgbe_hw *hw,
>> +                                    struct ixgbe_hw_dev_caps *dev_p,
>> +                                    struct ixgbe_aci_cmd_list_caps_elem *cap)
>> +{
>> +       u32 number = cap->number;
>> +
>> +       dev_p->num_vsi_allocd_to_host = number;
>> +}
>> +
>> +/**
>> + * ixgbe_parse_fdir_dev_caps - Parse IXGBE_ACI_CAPS_FD device caps
>> + * @hw: pointer to the HW struct
>> + * @dev_p: pointer to device capabilities structure
>> + * @cap: capability element to parse
>> + *
>> + * Parse IXGBE_ACI_CAPS_FD for device capabilities.
>> + */
>> +static void ixgbe_parse_fdir_dev_caps(struct ixgbe_hw *hw,
>> +                                     struct ixgbe_hw_dev_caps *dev_p,
>> +                                     struct ixgbe_aci_cmd_list_caps_elem *cap)
>> +{
>> +       u32 number = cap->number;
>> +
>> +       dev_p->num_flow_director_fltr = number;
>> +}
>> +
>> +/**
>> + * ixgbe_parse_dev_caps - Parse device capabilities
>> + * @hw: pointer to the HW struct
>> + * @dev_p: pointer to device capabilities structure
>> + * @buf: buffer containing the device capability records
>> + * @cap_count: the number of capabilities
>> + *
>> + * Helper device to parse device (0x000B) capabilities list. For
>> + * capabilities shared between device and function, this relies on
>> + * ixgbe_parse_e610_caps.
>> + *
>> + * Loop through the list of provided capabilities and extract the relevant
>> + * data into the device capabilities structured.
>> + */
>> +static void ixgbe_parse_dev_caps(struct ixgbe_hw *hw,
>> +                                struct ixgbe_hw_dev_caps *dev_p,
>> +                                void *buf, u32 cap_count)
>> +{
>> +       struct ixgbe_aci_cmd_list_caps_elem *cap_resp;
>> +       u32 i;
>> +
>> +       cap_resp = (struct ixgbe_aci_cmd_list_caps_elem *)buf;
>> +
>> +       memset(dev_p, 0, sizeof(*dev_p));
>> +
>> +       for (i = 0; i < cap_count; i++) {
>> +               u16 cap = cap_resp[i].cap;
>> +
>> +               ixgbe_parse_e610_caps(hw, &dev_p->common_cap, &cap_resp[i],
>> +                                     "dev caps");
>> +
>> +               switch (cap) {
>> +               case IXGBE_ACI_CAPS_VALID_FUNCTIONS:
>> +                       ixgbe_parse_valid_functions_cap(hw, dev_p,
>> +                                                       &cap_resp[i]);
>> +                       break;
>> +               case IXGBE_ACI_CAPS_VF:
>> +                       ixgbe_parse_vf_dev_caps(hw, dev_p, &cap_resp[i]);
>> +                       break;
>> +               case IXGBE_ACI_CAPS_VSI:
>> +                       ixgbe_parse_vsi_dev_caps(hw, dev_p, &cap_resp[i]);
>> +                       break;
>> +               case  IXGBE_ACI_CAPS_FD:
>> +                       ixgbe_parse_fdir_dev_caps(hw, dev_p, &cap_resp[i]);
>> +                       break;
>> +               default:
>> +                       /* Don't list common capabilities as unknown */
>> +                       break;
>> +               }
>> +       }
>> +}
>> +
>> +/**
>> + * ixgbe_parse_vf_func_caps - Parse IXGBE_ACI_CAPS_VF function caps
>> + * @hw: pointer to the HW struct
>> + * @func_p: pointer to function capabilities structure
>> + * @cap: pointer to the capability element to parse
>> + *
>> + * Extract function capabilities for IXGBE_ACI_CAPS_VF.
>> + */
>> +static void ixgbe_parse_vf_func_caps(struct ixgbe_hw *hw,
>> +                                    struct ixgbe_hw_func_caps *func_p,
>> +                                    struct ixgbe_aci_cmd_list_caps_elem *cap)
>> +{
>> +       u32 logical_id = cap->logical_id;
>> +       u32 number = cap->number;
>> +
>> +       func_p->num_allocd_vfs = number;
>> +       func_p->vf_base_id = logical_id;
>> +}
>> +
>> +/**
>> + * ixgbe_get_num_per_func - determine number of resources per PF
>> + * @hw: pointer to the HW structure
>> + * @max: value to be evenly split between each PF
>> + *
>> + * Determine the number of valid functions by going through the bitmap returned
>> + * from parsing capabilities and use this to calculate the number of resources
>> + * per PF based on the max value passed in.
>> + *
>> + * Return: the number of resources per PF or 0, if no PH are available.
>> + */
>> +static u32 ixgbe_get_num_per_func(struct ixgbe_hw *hw, u32 max)
>> +{
>> +#define IXGBE_CAPS_VALID_FUNCS_M       GENMASK(7, 0)
>> +       u8 funcs = hweight8(hw->dev_caps.common_cap.valid_functions &
>> +                           IXGBE_CAPS_VALID_FUNCS_M);
>> +
>> +       return funcs ? (max / funcs) : 0;
>> +}
>> +
>> +/**
>> + * ixgbe_parse_vsi_func_caps - Parse IXGBE_ACI_CAPS_VSI function caps
>> + * @hw: pointer to the HW struct
>> + * @func_p: pointer to function capabilities structure
>> + * @cap: pointer to the capability element to parse
>> + *
>> + * Extract function capabilities for IXGBE_ACI_CAPS_VSI.
>> + */
>> +static void ixgbe_parse_vsi_func_caps(struct ixgbe_hw *hw,
>> +                                     struct ixgbe_hw_func_caps *func_p,
>> +                                     struct ixgbe_aci_cmd_list_caps_elem *cap)
>> +{
>> +       func_p->guar_num_vsi = ixgbe_get_num_per_func(hw, IXGBE_MAX_VSI);
>> +}
>> +
>> +/**
>> + * ixgbe_parse_func_caps - Parse function capabilities
>> + * @hw: pointer to the HW struct
>> + * @func_p: pointer to function capabilities structure
>> + * @buf: buffer containing the function capability records
>> + * @cap_count: the number of capabilities
>> + *
>> + * Helper function to parse function (0x000A) capabilities list. For
>> + * capabilities shared between device and function, this relies on
>> + * ixgbe_parse_e610_caps.
>> + *
>> + * Loop through the list of provided capabilities and extract the relevant
>> + * data into the function capabilities structured.
>> + */
>> +static void ixgbe_parse_func_caps(struct ixgbe_hw *hw,
>> +                                 struct ixgbe_hw_func_caps *func_p,
>> +                                 void *buf, u32 cap_count)
>> +{
>> +       struct ixgbe_aci_cmd_list_caps_elem *cap_resp;
>> +       u32 i;
>> +
>> +       cap_resp = (struct ixgbe_aci_cmd_list_caps_elem *)buf;
>> +
>> +       memset(func_p, 0, sizeof(*func_p));
>> +
>> +       for (i = 0; i < cap_count; i++) {
>> +               u16 cap = cap_resp[i].cap;
>> +
>> +               ixgbe_parse_e610_caps(hw, &func_p->common_cap,
>> +                                     &cap_resp[i], "func caps");
>> +
>> +               switch (cap) {
>> +               case IXGBE_ACI_CAPS_VF:
>> +                       ixgbe_parse_vf_func_caps(hw, func_p, &cap_resp[i]);
>> +                       break;
>> +               case IXGBE_ACI_CAPS_VSI:
>> +                       ixgbe_parse_vsi_func_caps(hw, func_p, &cap_resp[i]);
>> +                       break;
>> +               default:
>> +                       /* Don't list common capabilities as unknown */
>> +                       break;
>> +               }
>> +       }
>> +}
>> +
>> +/**
>> + * ixgbe_aci_list_caps - query function/device capabilities
>> + * @hw: pointer to the HW struct
>> + * @buf: a buffer to hold the capabilities
>> + * @buf_size: size of the buffer
>> + * @cap_count: if not NULL, set to the number of capabilities reported
>> + * @opc: capabilities type to discover, device or function
>> + *
>> + * Get the function (0x000A) or device (0x000B) capabilities description from
>> + * firmware and store it in the buffer.
>> + *
>> + * If the cap_count pointer is not NULL, then it is set to the number of
>> + * capabilities firmware will report. Note that if the buffer size is too
>> + * small, it is possible the command will return -ENOMEM. The
>> + * cap_count will still be updated in this case. It is recommended that the
>> + * buffer size be set to IXGBE_ACI_MAX_BUFFER_SIZE (the largest possible
>> + * buffer that firmware could return) to avoid this.
>> + *
>> + * Return: the exit code of the operation.
>> + * Exit code of -ENOMEM means the buffer size is too small.
>> + */
>> +int ixgbe_aci_list_caps(struct ixgbe_hw *hw, void *buf, u16 buf_size,
>> +                       u32 *cap_count, enum ixgbe_aci_opc opc)
>> +{
>> +       struct ixgbe_aci_cmd_list_caps *cmd;
>> +       struct ixgbe_aci_desc desc;
>> +       int err;
>> +
>> +       cmd = &desc.params.get_cap;
>> +
>> +       if (opc != ixgbe_aci_opc_list_func_caps &&
>> +           opc != ixgbe_aci_opc_list_dev_caps)
>> +               return -EINVAL;
>> +
>> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, opc);
>> +       err = ixgbe_aci_send_cmd(hw, &desc, buf, buf_size);
>> +
>> +       if (cap_count)
>[Kalesh] Do you need a check for !err as well here?
>> +               *cap_count = cmd->count;
>> +
>> +       return err;
>> +}
>> +
>> +/**
>> + * ixgbe_discover_dev_caps - Read and extract device capabilities
>> + * @hw: pointer to the hardware structure
>> + * @dev_caps: pointer to device capabilities structure
>> + *
>> + * Read the device capabilities and extract them into the dev_caps structure
>> + * for later use.
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_discover_dev_caps(struct ixgbe_hw *hw,
>> +                           struct ixgbe_hw_dev_caps *dev_caps)
>> +{
>> +       u8 *cbuf __free(kfree);
>> +       u32 cap_count;
>> +       int err;
>> +
>> +       cbuf = kzalloc(IXGBE_ACI_MAX_BUFFER_SIZE, GFP_KERNEL);
>> +       if (!cbuf)
>> +               return -ENOMEM;
>> +       /* Although the driver doesn't know the number of capabilities the
>> +        * device will return, we can simply send a 4KB buffer, the maximum
>> +        * possible size that firmware can return.
>> +        */
>> +       cap_count = IXGBE_ACI_MAX_BUFFER_SIZE /
>> +                   sizeof(struct ixgbe_aci_cmd_list_caps_elem);
>> +
>> +       err = ixgbe_aci_list_caps(hw, cbuf, IXGBE_ACI_MAX_BUFFER_SIZE,
>> +                                 &cap_count,
>> +                                 ixgbe_aci_opc_list_dev_caps);
>> +       if (err)
>> +               return err;
>> +
>> +       ixgbe_parse_dev_caps(hw, dev_caps, cbuf, cap_count);
>> +
>> +       return 0;
>> +}
>> +
>> +/**
>> + * ixgbe_discover_func_caps - Read and extract function capabilities
>> + * @hw: pointer to the hardware structure
>> + * @func_caps: pointer to function capabilities structure
>> + *
>> + * Read the function capabilities and extract them into the func_caps structure
>> + * for later use.
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_discover_func_caps(struct ixgbe_hw *hw,
>> +                            struct ixgbe_hw_func_caps *func_caps)
>> +{
>> +       u8 *cbuf __free(kfree);
>> +       u32 cap_count;
>> +       int err;
>> +
>> +       cbuf = kzalloc(IXGBE_ACI_MAX_BUFFER_SIZE, GFP_KERNEL);
>> +       if (!cbuf)
>> +               return -ENOMEM;
>> +
>> +       /* Although the driver doesn't know the number of capabilities the
>> +        * device will return, we can simply send a 4KB buffer, the maximum
>> +        * possible size that firmware can return.
>> +        */
>> +       cap_count = IXGBE_ACI_MAX_BUFFER_SIZE /
>> +                   sizeof(struct ixgbe_aci_cmd_list_caps_elem);
>> +
>> +       err = ixgbe_aci_list_caps(hw, cbuf, IXGBE_ACI_MAX_BUFFER_SIZE,
>> +                                 &cap_count,
>> +                                 ixgbe_aci_opc_list_func_caps);
>> +       if (err)
>> +               return err;
>> +
>> +       ixgbe_parse_func_caps(hw, func_caps, cbuf, cap_count);
>> +
>> +       return 0;
>> +}
>> +
>> +/**
>> + * ixgbe_get_caps - get info about the HW
>> + * @hw: pointer to the hardware structure
>> + *
>> + * Retrieve both device and function capabilities.
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_get_caps(struct ixgbe_hw *hw)
>> +{
>> +       int err;
>> +
>> +       err = ixgbe_discover_dev_caps(hw, &hw->dev_caps);
>> +       if (err)
>> +               return err;
>> +
>> +       return ixgbe_discover_func_caps(hw, &hw->func_caps);
>> +}
>> +
>> +/**
>> + * ixgbe_aci_disable_rxen - disable RX
>> + * @hw: pointer to the HW struct
>> + *
>> + * Request a safe disable of Receive Enable using ACI command (0x000C).
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_aci_disable_rxen(struct ixgbe_hw *hw)
>> +{
>> +       struct ixgbe_aci_cmd_disable_rxen *cmd;
>> +       struct ixgbe_aci_desc desc;
>> +
>> +       cmd = &desc.params.disable_rxen;
>> +
>> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_disable_rxen);
>> +
>> +       cmd->lport_num = hw->bus.func;
>> +
>> +       return ixgbe_aci_send_cmd(hw, &desc, NULL, 0);
>> +}
>> +
>> +/**
>> + * ixgbe_aci_get_phy_caps - returns PHY capabilities
>> + * @hw: pointer to the HW struct
>> + * @qual_mods: report qualified modules
>> + * @report_mode: report mode capabilities
>> + * @pcaps: structure for PHY capabilities to be filled
>> + *
>> + * Returns the various PHY capabilities supported on the Port
>> + * using ACI command (0x0600).
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_aci_get_phy_caps(struct ixgbe_hw *hw, bool qual_mods, u8 report_mode,
>> +                          struct ixgbe_aci_cmd_get_phy_caps_data *pcaps)
>> +{
>> +       struct ixgbe_aci_cmd_get_phy_caps *cmd;
>> +       u16 pcaps_size = sizeof(*pcaps);
>> +       struct ixgbe_aci_desc desc;
>> +       int err;
>> +
>> +       cmd = &desc.params.get_phy;
>> +
>> +       if (!pcaps || (report_mode & ~IXGBE_ACI_REPORT_MODE_M))
>> +               return -EINVAL;
>> +
>> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_phy_caps);
>> +
>> +       if (qual_mods)
>> +               cmd->param0 |= IXGBE_ACI_GET_PHY_RQM;
>> +
>> +       cmd->param0 |= report_mode;
>> +       err = ixgbe_aci_send_cmd(hw, &desc, pcaps, pcaps_size);
>> +
>> +       if (!err && report_mode == IXGBE_ACI_REPORT_TOPO_CAP_MEDIA) {
>> +               hw->phy.phy_type_low = pcaps->phy_type_low;
>> +               hw->phy.phy_type_high = pcaps->phy_type_high;
>> +               memcpy(hw->link.link_info.module_type, &pcaps->module_type,
>> +                      sizeof(hw->link.link_info.module_type));
>> +       }
>> +
>> +       return err;
>> +}
>> +
>> +/**
>> + * ixgbe_copy_phy_caps_to_cfg - Copy PHY ability data to configuration data
>> + * @caps: PHY ability structure to copy data from
>> + * @cfg: PHY configuration structure to copy data to
>> + *
>> + * Helper function to copy data from PHY capabilities data structure
>> + * to PHY configuration data structure
>> + */
>> +void ixgbe_copy_phy_caps_to_cfg(struct ixgbe_aci_cmd_get_phy_caps_data *caps,
>> +                               struct ixgbe_aci_cmd_set_phy_cfg_data *cfg)
>> +{
>> +       if (!caps || !cfg)
>> +               return;
>> +
>> +       memset(cfg, 0, sizeof(*cfg));
>> +       cfg->phy_type_low = caps->phy_type_low;
>> +       cfg->phy_type_high = caps->phy_type_high;
>> +       cfg->caps = caps->caps;
>> +       cfg->low_power_ctrl_an = caps->low_power_ctrl_an;
>> +       cfg->eee_cap = caps->eee_cap;
>> +       cfg->eeer_value = caps->eeer_value;
>> +       cfg->link_fec_opt = caps->link_fec_options;
>> +       cfg->module_compliance_enforcement =
>> +               caps->module_compliance_enforcement;
>> +}
>> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
>> index 18b831b..5c5a676 100644
>> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
>> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
>> @@ -15,5 +15,17 @@ void ixgbe_fill_dflt_direct_cmd_desc(struct ixgbe_aci_desc *desc, u16 opcode);
>>  int ixgbe_acquire_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res,
>>                       enum ixgbe_aci_res_access_type access, u32 timeout);
>>  void ixgbe_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res);
>> +int ixgbe_aci_list_caps(struct ixgbe_hw *hw, void *buf, u16 buf_size,
>> +                       u32 *cap_count, enum ixgbe_aci_opc opc);
>> +int ixgbe_discover_dev_caps(struct ixgbe_hw *hw,
>> +                           struct ixgbe_hw_dev_caps *dev_caps);
>> +int ixgbe_discover_func_caps(struct ixgbe_hw *hw,
>> +                            struct ixgbe_hw_func_caps *func_caps);
>> +int ixgbe_get_caps(struct ixgbe_hw *hw);
>> +int ixgbe_aci_disable_rxen(struct ixgbe_hw *hw);
>> +int ixgbe_aci_get_phy_caps(struct ixgbe_hw *hw, bool qual_mods, u8 report_mode,
>> +                          struct ixgbe_aci_cmd_get_phy_caps_data *pcaps);
>> +void ixgbe_copy_phy_caps_to_cfg(struct ixgbe_aci_cmd_get_phy_caps_data *caps,
>> +                               struct ixgbe_aci_cmd_set_phy_cfg_data *cfg);
>>
>>  #endif /* _IXGBE_E610_H_ */
>> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
>> index 8b8404d..0302a21 100644
>> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
>> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
>> @@ -43,6 +43,7 @@
>>  #include "ixgbe.h"
>>  #include "ixgbe_common.h"
>>  #include "ixgbe_dcb_82599.h"
>> +#include "ixgbe_e610.h"
>>  #include "ixgbe_phy.h"
>>  #include "ixgbe_sriov.h"
>>  #include "ixgbe_model.h"
>> @@ -10932,6 +10933,13 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>>         if (err)
>>                 goto err_sw_init;
>>
>> +       if (adapter->hw.mac.type == ixgbe_mac_e610) {
>> +               err = ixgbe_get_caps(&adapter->hw);
>> +               if (err)
>> +                       dev_err(&pdev->dev,
>> +                               "ixgbe_get_caps failed %d\n", err);
>[Kalesh] You can fit this log in one line
>> +       }
>> +
>>         if (adapter->hw.mac.type == ixgbe_mac_82599EB)
>>                 adapter->flags2 |= IXGBE_FLAG2_AUTO_DISABLE_VF;
>>
>> --
>> 2.43.0
>>
>>
>
>
>-- 
>Regards,
>Kalesh A P

^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: [PATCH iwl-next v9 3/7] ixgbe: Add link management support for E610 device
  2024-10-17 13:26   ` Kalesh Anakkur Purayil
@ 2024-10-21  9:01     ` Kwapulinski, Piotr
  0 siblings, 0 replies; 16+ messages in thread
From: Kwapulinski, Piotr @ 2024-10-21  9:01 UTC (permalink / raw)
  To: Kalesh Anakkur Purayil
  Cc: intel-wired-lan@lists.osuosl.org, netdev@vger.kernel.org,
	Wegrzyn, Stefan, Jagielski, Jedrzej, Glaza, Jan

>-----Original Message-----
>From: Kalesh Anakkur Purayil <kalesh-anakkur.purayil@broadcom.com> 
>Sent: Thursday, October 17, 2024 3:27 PM
>To: Kwapulinski, Piotr <piotr.kwapulinski@intel.com>
>Cc: intel-wired-lan@lists.osuosl.org; netdev@vger.kernel.org; Wegrzyn, Stefan <stefan.wegrzyn@intel.com>; Jagielski, Jedrzej <jedrzej.jagielski@intel.com>; Glaza, Jan <jan.glaza@intel.com>
>Subject: Re: [PATCH iwl-next v9 3/7] ixgbe: Add link management support for E610 device
>
>On Thu, Oct 3, 2024 at 7:49 PM Piotr Kwapulinski
><piotr.kwapulinski@intel.com> wrote:
>>
>> Add low level link management support for E610 device. Link management
>> operations are handled via the Admin Command Interface. Add the following
>> link management operations:
>> - get link capabilities
>> - set up link
>> - get media type
>> - get link status, link status events
>> - link power management
>>
>> Co-developed-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
>> Signed-off-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
>> Co-developed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
>> Signed-off-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
>> Reviewed-by: Jan Glaza <jan.glaza@intel.com>
>> Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>
>> ---
>>  drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 1091 +++++++++++++++++
>>  drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h |   32 +
>>  .../ethernet/intel/ixgbe/ixgbe_type_e610.h    |    1 +
>>  3 files changed, 1124 insertions(+)
>>
>> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
>> index 3bc88df..c0c740f 100644
>> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
>> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
>> @@ -1033,3 +1033,1094 @@ void ixgbe_copy_phy_caps_to_cfg(struct ixgbe_aci_cmd_get_phy_caps_data *caps,
>>         cfg->module_compliance_enforcement =
>>                 caps->module_compliance_enforcement;
>>  }
>> +
>> +/**
>> + * ixgbe_aci_set_phy_cfg - set PHY configuration
>> + * @hw: pointer to the HW struct
>> + * @cfg: structure with PHY configuration data to be set
>> + *
>> + * Set the various PHY configuration parameters supported on the Port
>> + * using ACI command (0x0601).
>> + * One or more of the Set PHY config parameters may be ignored in an MFP
>> + * mode as the PF may not have the privilege to set some of the PHY Config
>> + * parameters.
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_aci_set_phy_cfg(struct ixgbe_hw *hw,
>> +                         struct ixgbe_aci_cmd_set_phy_cfg_data *cfg)
>> +{
>> +       struct ixgbe_aci_desc desc;
>> +       int err;
>> +
>> +       if (!cfg)
>> +               return -EINVAL;
>> +
>> +       /* Ensure that only valid bits of cfg->caps can be turned on. */
>> +       cfg->caps &= IXGBE_ACI_PHY_ENA_VALID_MASK;
>> +
>> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_set_phy_cfg);
>> +       desc.params.set_phy.lport_num = hw->bus.func;
>> +       desc.flags |= IXGBE_ACI_FLAG_RD;
>> +
>> +       err = ixgbe_aci_send_cmd(hw, &desc, cfg, sizeof(*cfg));
>> +
>[Kalesh] There is no need of an empty line here
Will do

>> +       if (!err)
>> +               hw->phy.curr_user_phy_cfg = *cfg;
>> +
>> +       return err;
>> +}
>> +
>> +/**
>> + * ixgbe_aci_set_link_restart_an - set up link and restart AN
>> + * @hw: pointer to the HW struct
>> + * @ena_link: if true: enable link, if false: disable link
>> + *
>> + * Function sets up the link and restarts the Auto-Negotiation over the link.
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_aci_set_link_restart_an(struct ixgbe_hw *hw, bool ena_link)
>> +{
>> +       struct ixgbe_aci_cmd_restart_an *cmd;
>> +       struct ixgbe_aci_desc desc;
>> +
>> +       cmd = &desc.params.restart_an;
>> +
>> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_restart_an);
>> +
>> +       cmd->cmd_flags = IXGBE_ACI_RESTART_AN_LINK_RESTART;
>> +       cmd->lport_num = hw->bus.func;
>> +       if (ena_link)
>> +               cmd->cmd_flags |= IXGBE_ACI_RESTART_AN_LINK_ENABLE;
>> +       else
>> +               cmd->cmd_flags &= ~IXGBE_ACI_RESTART_AN_LINK_ENABLE;
>> +
>> +       return ixgbe_aci_send_cmd(hw, &desc, NULL, 0);
>> +}
>> +
>> +/**
>> + * ixgbe_is_media_cage_present - check if media cage is present
>> + * @hw: pointer to the HW struct
>> + *
>> + * Identify presence of media cage using the ACI command (0x06E0).
>> + *
>> + * Return: true if media cage is present, else false. If no cage, then
>> + * media type is backplane or BASE-T.
>> + */
>> +static bool ixgbe_is_media_cage_present(struct ixgbe_hw *hw)
>> +{
>> +       struct ixgbe_aci_cmd_get_link_topo *cmd;
>> +       struct ixgbe_aci_desc desc;
>> +
>> +       cmd = &desc.params.get_link_topo;
>> +
>> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_link_topo);
>> +
>> +       cmd->addr.topo_params.node_type_ctx =
>> +               FIELD_PREP(IXGBE_ACI_LINK_TOPO_NODE_CTX_M,
>> +                          IXGBE_ACI_LINK_TOPO_NODE_CTX_PORT);
>> +
>> +       /* Set node type. */
>> +       cmd->addr.topo_params.node_type_ctx |=
>> +               FIELD_PREP(IXGBE_ACI_LINK_TOPO_NODE_TYPE_M,
>> +                          IXGBE_ACI_LINK_TOPO_NODE_TYPE_CAGE);
>> +
>> +       /* Node type cage can be used to determine if cage is present. If AQC
>> +        * returns error (ENOENT), then no cage present. If no cage present then
>> +        * connection type is backplane or BASE-T.
>> +        */
>> +       return ixgbe_aci_get_netlist_node(hw, cmd, NULL, NULL);
>> +}
>> +
>> +/**
>> + * ixgbe_get_media_type_from_phy_type - Gets media type based on phy type
>> + * @hw: pointer to the HW struct
>> + *
>> + * Try to identify the media type based on the phy type.
>> + * If more than one media type, the ixgbe_media_type_unknown is returned.
>> + * First, phy_type_low is checked, then phy_type_high.
>> + * If none are identified, the ixgbe_media_type_unknown is returned
>> + *
>> + * Return: type of a media based on phy type in form of enum.
>> + */
>> +static enum ixgbe_media_type
>> +ixgbe_get_media_type_from_phy_type(struct ixgbe_hw *hw)
>> +{
>> +       struct ixgbe_link_status *hw_link_info;
>> +
>> +       if (!hw)
>> +               return ixgbe_media_type_unknown;
>> +
>> +       hw_link_info = &hw->link.link_info;
>> +       if (hw_link_info->phy_type_low && hw_link_info->phy_type_high)
>> +               /* If more than one media type is selected, report unknown */
>> +               return ixgbe_media_type_unknown;
>> +
>> +       if (hw_link_info->phy_type_low) {
>> +               /* 1G SGMII is a special case where some DA cable PHYs
>> +                * may show this as an option when it really shouldn't
>> +                * be since SGMII is meant to be between a MAC and a PHY
>> +                * in a backplane. Try to detect this case and handle it
>> +                */
>> +               if (hw_link_info->phy_type_low == IXGBE_PHY_TYPE_LOW_1G_SGMII &&
>> +                   (hw_link_info->module_type[IXGBE_ACI_MOD_TYPE_IDENT] ==
>> +                   IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_ACTIVE ||
>> +                   hw_link_info->module_type[IXGBE_ACI_MOD_TYPE_IDENT] ==
>> +                   IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_PASSIVE))
>> +                       return ixgbe_media_type_da;
>> +
>> +               switch (hw_link_info->phy_type_low) {
>> +               case IXGBE_PHY_TYPE_LOW_1000BASE_SX:
>> +               case IXGBE_PHY_TYPE_LOW_1000BASE_LX:
>> +               case IXGBE_PHY_TYPE_LOW_10GBASE_SR:
>> +               case IXGBE_PHY_TYPE_LOW_10GBASE_LR:
>> +               case IXGBE_PHY_TYPE_LOW_25GBASE_SR:
>> +               case IXGBE_PHY_TYPE_LOW_25GBASE_LR:
>> +                       return ixgbe_media_type_fiber;
>> +               case IXGBE_PHY_TYPE_LOW_10G_SFI_AOC_ACC:
>> +               case IXGBE_PHY_TYPE_LOW_25G_AUI_AOC_ACC:
>> +                       return ixgbe_media_type_fiber;
>> +               case IXGBE_PHY_TYPE_LOW_100BASE_TX:
>> +               case IXGBE_PHY_TYPE_LOW_1000BASE_T:
>> +               case IXGBE_PHY_TYPE_LOW_2500BASE_T:
>> +               case IXGBE_PHY_TYPE_LOW_5GBASE_T:
>> +               case IXGBE_PHY_TYPE_LOW_10GBASE_T:
>> +               case IXGBE_PHY_TYPE_LOW_25GBASE_T:
>> +                       return ixgbe_media_type_copper;
>> +               case IXGBE_PHY_TYPE_LOW_10G_SFI_DA:
>> +               case IXGBE_PHY_TYPE_LOW_25GBASE_CR:
>> +               case IXGBE_PHY_TYPE_LOW_25GBASE_CR_S:
>> +               case IXGBE_PHY_TYPE_LOW_25GBASE_CR1:
>> +                       return ixgbe_media_type_da;
>> +               case IXGBE_PHY_TYPE_LOW_25G_AUI_C2C:
>> +                       if (ixgbe_is_media_cage_present(hw))
>> +                               return ixgbe_media_type_aui;
>> +                       fallthrough;
>> +               case IXGBE_PHY_TYPE_LOW_1000BASE_KX:
>> +               case IXGBE_PHY_TYPE_LOW_2500BASE_KX:
>> +               case IXGBE_PHY_TYPE_LOW_2500BASE_X:
>> +               case IXGBE_PHY_TYPE_LOW_5GBASE_KR:
>> +               case IXGBE_PHY_TYPE_LOW_10GBASE_KR_CR1:
>> +               case IXGBE_PHY_TYPE_LOW_10G_SFI_C2C:
>> +               case IXGBE_PHY_TYPE_LOW_25GBASE_KR:
>> +               case IXGBE_PHY_TYPE_LOW_25GBASE_KR1:
>> +               case IXGBE_PHY_TYPE_LOW_25GBASE_KR_S:
>> +                       return ixgbe_media_type_backplane;
>> +               }
>> +       } else {
>> +               switch (hw_link_info->phy_type_high) {
>> +               case IXGBE_PHY_TYPE_HIGH_10BASE_T:
>> +                       return ixgbe_media_type_copper;
>> +               }
>> +       }
>> +       return ixgbe_media_type_unknown;
>> +}
>> +
>> +/**
>> + * ixgbe_update_link_info - update status of the HW network link
>> + * @hw: pointer to the HW struct
>> + *
>> + * Update the status of the HW network link.
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_update_link_info(struct ixgbe_hw *hw)
>> +{
>> +       struct ixgbe_link_status *li;
>> +       int err;
>> +
>> +       if (!hw)
>> +               return -EINVAL;
>> +
>> +       li = &hw->link.link_info;
>> +
>> +       err = ixgbe_aci_get_link_info(hw, true, NULL);
>> +       if (err)
>> +               return err;
>> +
>> +       if (li->link_info & IXGBE_ACI_MEDIA_AVAILABLE) {
>[Kalesh] If you change the check as below, that would help code indentation:
Will do.

>if (!(li->link_info & IXGBE_ACI_MEDIA_AVAILABLE))
>      return 0;
>> +               struct ixgbe_aci_cmd_get_phy_caps_data __free(kfree) *pcaps;
>> +
>> +               pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
>> +               if (!pcaps)
>> +                       return -ENOMEM;
>> +
>> +               err = ixgbe_aci_get_phy_caps(hw, false,
>> +                                            IXGBE_ACI_REPORT_TOPO_CAP_MEDIA,
>> +                                            pcaps);
>> +
>> +               if (!err)
>> +                       memcpy(li->module_type, &pcaps->module_type,
>> +                              sizeof(li->module_type));
>> +       }
>> +
>> +       return err;
>> +}
>> +
>> +/**
>> + * ixgbe_get_link_status - get status of the HW network link
>> + * @hw: pointer to the HW struct
>> + * @link_up: pointer to bool (true/false = linkup/linkdown)
>> + *
>> + * Variable link_up is true if link is up, false if link is down.
>> + * The variable link_up is invalid if status is non zero. As a
>> + * result of this call, link status reporting becomes enabled
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_get_link_status(struct ixgbe_hw *hw, bool *link_up)
>> +{
>> +       if (!hw || !link_up)
>> +               return -EINVAL;
>> +
>> +       if (hw->link.get_link_info) {
>> +               int err = ixgbe_update_link_info(hw);
>> +
>> +               if (err)
>> +                       return err;
>> +       }
>> +
>> +       *link_up = hw->link.link_info.link_info & IXGBE_ACI_LINK_UP;
>> +
>> +       return 0;
>> +}
>> +
>> +/**
>> + * ixgbe_aci_get_link_info - get the link status
>> + * @hw: pointer to the HW struct
>> + * @ena_lse: enable/disable LinkStatusEvent reporting
>> + * @link: pointer to link status structure - optional
>> + *
>> + * Get the current Link Status using ACI command (0x607).
>> + * The current link can be optionally provided to update
>> + * the status.
>> + *
>> + * Return: the link status of the adapter.
>> + */
>> +int ixgbe_aci_get_link_info(struct ixgbe_hw *hw, bool ena_lse,
>> +                           struct ixgbe_link_status *link)
>> +{
>> +       struct ixgbe_aci_cmd_get_link_status_data link_data = { 0 };
>> +       struct ixgbe_aci_cmd_get_link_status *resp;
>> +       struct ixgbe_link_status *li_old, *li;
>> +       struct ixgbe_fc_info *hw_fc_info;
>> +       struct ixgbe_aci_desc desc;
>> +       bool tx_pause, rx_pause;
>> +       u8 cmd_flags;
>> +       int err;
>> +
>> +       if (!hw)
>> +               return -EINVAL;
>> +
>> +       li_old = &hw->link.link_info_old;
>> +       li = &hw->link.link_info;
>> +       hw_fc_info = &hw->fc;
>> +
>> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_link_status);
>> +       cmd_flags = (ena_lse) ? IXGBE_ACI_LSE_ENA : IXGBE_ACI_LSE_DIS;
>> +       resp = &desc.params.get_link_status;
>> +       resp->cmd_flags = cmd_flags;
>> +       resp->lport_num = hw->bus.func;
>> +
>> +       err = ixgbe_aci_send_cmd(hw, &desc, &link_data, sizeof(link_data));
>> +
>[Kalesh] there is no need of empty line here
Will do.

>> +       if (err)
>> +               return err;
>> +
>> +       /* Save off old link status information. */
>> +       *li_old = *li;
>> +
>> +       /* Update current link status information. */
>> +       li->link_speed = link_data.link_speed;
>> +       li->phy_type_low = link_data.phy_type_low;
>> +       li->phy_type_high = link_data.phy_type_high;
>> +       li->link_info = link_data.link_info;
>> +       li->link_cfg_err = link_data.link_cfg_err;
>> +       li->an_info = link_data.an_info;
>> +       li->ext_info = link_data.ext_info;
>> +       li->max_frame_size = link_data.max_frame_size;
>> +       li->fec_info = link_data.cfg & IXGBE_ACI_FEC_MASK;
>> +       li->topo_media_conflict = link_data.topo_media_conflict;
>> +       li->pacing = link_data.cfg & (IXGBE_ACI_CFG_PACING_M |
>> +                                     IXGBE_ACI_CFG_PACING_TYPE_M);
>> +
>> +       /* Update fc info. */
>> +       tx_pause = !!(link_data.an_info & IXGBE_ACI_LINK_PAUSE_TX);
>> +       rx_pause = !!(link_data.an_info & IXGBE_ACI_LINK_PAUSE_RX);
>> +       if (tx_pause && rx_pause)
>> +               hw_fc_info->current_mode = ixgbe_fc_full;
>> +       else if (tx_pause)
>> +               hw_fc_info->current_mode = ixgbe_fc_tx_pause;
>> +       else if (rx_pause)
>> +               hw_fc_info->current_mode = ixgbe_fc_rx_pause;
>> +       else
>> +               hw_fc_info->current_mode = ixgbe_fc_none;
>> +
>> +       li->lse_ena = !!(resp->cmd_flags & IXGBE_ACI_LSE_IS_ENABLED);
>> +
>> +       /* Save link status information. */
>> +       if (link)
>> +               *link = *li;
>> +
>> +       /* Flag cleared so calling functions don't call AQ again. */
>> +       hw->link.get_link_info = false;
>> +
>> +       return 0;
>> +}
>> +
>> +/**
>> + * ixgbe_aci_set_event_mask - set event mask
>> + * @hw: pointer to the HW struct
>> + * @port_num: port number of the physical function
>> + * @mask: event mask to be set
>> + *
>> + * Set the event mask using ACI command (0x0613).
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_aci_set_event_mask(struct ixgbe_hw *hw, u8 port_num, u16 mask)
>> +{
>> +       struct ixgbe_aci_cmd_set_event_mask *cmd;
>> +       struct ixgbe_aci_desc desc;
>> +
>> +       cmd = &desc.params.set_event_mask;
>> +
>> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_set_event_mask);
>> +
>> +       cmd->lport_num = port_num;
>> +
>> +       cmd->event_mask = mask;
>> +       return ixgbe_aci_send_cmd(hw, &desc, NULL, 0);
>> +}
>> +
>> +/**
>> + * ixgbe_configure_lse - enable/disable link status events
>> + * @hw: pointer to the HW struct
>> + * @activate: true for enable lse, false otherwise
>> + * @mask: event mask to be set; a set bit means deactivation of the
>> + * corresponding event
>> + *
>> + * Set the event mask and then enable or disable link status events
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_configure_lse(struct ixgbe_hw *hw, bool activate, u16 mask)
>> +{
>> +       int err;
>> +
>> +       err = ixgbe_aci_set_event_mask(hw, (u8)hw->bus.func, mask);
>> +       if (err)
>> +               return err;
>> +
>> +       /* Enabling link status events generation by fw */
>> +       err = ixgbe_aci_get_link_info(hw, activate, NULL);
>[Kalesh] You can simplify this as:
>return ixgbe_aci_get_link_info(hw, activate, NULL);
Will do.

>> +       if (err)
>> +               return err;
>> +
>> +       return 0;
>> +}
>> +
>> +/**
>> + * ixgbe_get_media_type_e610 - Gets media type
>> + * @hw: pointer to the HW struct
>> + *
>> + * In order to get the media type, the function gets PHY
>> + * capabilities and later on use them to identify the PHY type
>> + * checking phy_type_high and phy_type_low.
>> + *
>> + * Return: the type of media in form of ixgbe_media_type enum
>> + * or ixgbe_media_type_unknown in case of an error.
>> + */
>> +enum ixgbe_media_type ixgbe_get_media_type_e610(struct ixgbe_hw *hw)
>> +{
>> +       struct ixgbe_aci_cmd_get_phy_caps_data pcaps;
>> +       int rc;
>> +
>> +       rc = ixgbe_update_link_info(hw);
>> +       if (rc)
>> +               return ixgbe_media_type_unknown;
>> +
>> +       /* If there is no link but PHY (dongle) is available SW should use
>> +        * Get PHY Caps admin command instead of Get Link Status, find most
>> +        * significant bit that is set in PHY types reported by the command
>> +        * and use it to discover media type.
>> +        */
>> +       if (!(hw->link.link_info.link_info & IXGBE_ACI_LINK_UP) &&
>> +           (hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE)) {
>> +               int highest_bit;
>> +
>> +               /* Get PHY Capabilities */
>> +               rc = ixgbe_aci_get_phy_caps(hw, false,
>> +                                           IXGBE_ACI_REPORT_TOPO_CAP_MEDIA,
>> +                                           &pcaps);
>> +               if (rc)
>> +                       return ixgbe_media_type_unknown;
>> +
>> +               highest_bit = fls64(pcaps.phy_type_high);
>> +               if (highest_bit) {
>> +                       hw->link.link_info.phy_type_high =
>> +                               BIT_ULL(highest_bit - 1);
>> +                       hw->link.link_info.phy_type_low = 0;
>> +               } else {
>> +                       highest_bit = fls64(pcaps.phy_type_low);
>> +                       if (highest_bit)
>> +                               hw->link.link_info.phy_type_low =
>> +                                       BIT_ULL(highest_bit - 1);
>> +               }
>> +       }
>> +
>> +       /* Based on link status or search above try to discover media type. */
>> +       hw->phy.media_type = ixgbe_get_media_type_from_phy_type(hw);
>> +
>> +       return hw->phy.media_type;
>> +}
>> +
>> +/**
>> + * ixgbe_setup_link_e610 - Set up link
>> + * @hw: pointer to hardware structure
>> + * @speed: new link speed
>> + * @autoneg_wait: true when waiting for completion is needed
>> + *
>> + * Set up the link with the specified speed.
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_setup_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed speed,
>> +                         bool autoneg_wait)
>> +{
>> +       /* Simply request FW to perform proper PHY setup */
>> +       return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait);
>> +}
>> +
>> +/**
>> + * ixgbe_check_link_e610 - Determine link and speed status
>> + * @hw: pointer to hardware structure
>> + * @speed: pointer to link speed
>> + * @link_up: true when link is up
>> + * @link_up_wait_to_complete: bool used to wait for link up or not
>> + *
>> + * Determine if the link is up and the current link speed
>> + * using ACI command (0x0607).
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_check_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
>> +                         bool *link_up, bool link_up_wait_to_complete)
>> +{
>> +       int err;
>> +       u32 i;
>> +
>> +       if (!speed || !link_up)
>> +               return -EINVAL;
>> +
>> +       /* Set get_link_info flag to ensure that fresh
>> +        * link information will be obtained from FW
>> +        * by sending Get Link Status admin command.
>> +        */
>> +       hw->link.get_link_info = true;
>> +
>> +       /* Update link information in adapter context. */
>> +       err = ixgbe_get_link_status(hw, link_up);
>> +       if (err)
>> +               return err;
>> +
>> +       /* Wait for link up if it was requested. */
>> +       if (link_up_wait_to_complete && !(*link_up)) {
>> +               for (i = 0; i < hw->mac.max_link_up_time; i++) {
>> +                       msleep(100);
>> +                       hw->link.get_link_info = true;
>> +                       err = ixgbe_get_link_status(hw, link_up);
>> +                       if (err)
>> +                               return err;
>> +                       if (*link_up)
>> +                               break;
>> +               }
>> +       }
>> +
>> +       /* Use link information in adapter context updated by the call
>> +        * to ixgbe_get_link_status() to determine current link speed.
>> +        * Link speed information is valid only when link up was
>> +        * reported by FW.
>> +        */
>> +       if (*link_up) {
>> +               switch (hw->link.link_info.link_speed) {
>> +               case IXGBE_ACI_LINK_SPEED_10MB:
>> +                       *speed = IXGBE_LINK_SPEED_10_FULL;
>> +                       break;
>> +               case IXGBE_ACI_LINK_SPEED_100MB:
>> +                       *speed = IXGBE_LINK_SPEED_100_FULL;
>> +                       break;
>> +               case IXGBE_ACI_LINK_SPEED_1000MB:
>> +                       *speed = IXGBE_LINK_SPEED_1GB_FULL;
>> +                       break;
>> +               case IXGBE_ACI_LINK_SPEED_2500MB:
>> +                       *speed = IXGBE_LINK_SPEED_2_5GB_FULL;
>> +                       break;
>> +               case IXGBE_ACI_LINK_SPEED_5GB:
>> +                       *speed = IXGBE_LINK_SPEED_5GB_FULL;
>> +                       break;
>> +               case IXGBE_ACI_LINK_SPEED_10GB:
>> +                       *speed = IXGBE_LINK_SPEED_10GB_FULL;
>> +                       break;
>> +               default:
>> +                       *speed = IXGBE_LINK_SPEED_UNKNOWN;
>> +                       break;
>> +               }
>> +       } else {
>> +               *speed = IXGBE_LINK_SPEED_UNKNOWN;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +/**
>> + * ixgbe_get_link_capabilities_e610 - Determine link capabilities
>> + * @hw: pointer to hardware structure
>> + * @speed: pointer to link speed
>> + * @autoneg: true when autoneg or autotry is enabled
>> + *
>> + * Determine speed and AN parameters of a link.
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_get_link_capabilities_e610(struct ixgbe_hw *hw,
>> +                                    ixgbe_link_speed *speed,
>> +                                    bool *autoneg)
>> +{
>> +       if (!speed || !autoneg)
>> +               return -EINVAL;
>> +
>> +       *autoneg = true;
>> +       *speed = hw->phy.speeds_supported;
>> +
>> +       return 0;
>> +}
>> +
>> +/**
>> + * ixgbe_cfg_phy_fc - Configure PHY Flow Control (FC) data based on FC mode
>> + * @hw: pointer to hardware structure
>> + * @cfg: PHY configuration data to set FC mode
>> + * @req_mode: FC mode to configure
>> + *
>> + * Configures PHY Flow Control according to the provided configuration.
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_cfg_phy_fc(struct ixgbe_hw *hw,
>> +                    struct ixgbe_aci_cmd_set_phy_cfg_data *cfg,
>> +                    enum ixgbe_fc_mode req_mode)
>> +{
>> +       u8 pause_mask = 0x0;
>> +
>> +       if (!cfg)
>> +               return -EINVAL;
>> +
>> +       switch (req_mode) {
>> +       case ixgbe_fc_full:
>> +               pause_mask |= IXGBE_ACI_PHY_EN_TX_LINK_PAUSE;
>> +               pause_mask |= IXGBE_ACI_PHY_EN_RX_LINK_PAUSE;
>> +               break;
>> +       case ixgbe_fc_rx_pause:
>> +               pause_mask |= IXGBE_ACI_PHY_EN_RX_LINK_PAUSE;
>> +               break;
>> +       case ixgbe_fc_tx_pause:
>> +               pause_mask |= IXGBE_ACI_PHY_EN_TX_LINK_PAUSE;
>> +               break;
>> +       default:
>> +               break;
>> +       }
>> +
>> +       /* Clear the old pause settings. */
>> +       cfg->caps &= ~(IXGBE_ACI_PHY_EN_TX_LINK_PAUSE |
>> +               IXGBE_ACI_PHY_EN_RX_LINK_PAUSE);
>> +
>> +       /* Set the new capabilities. */
>> +       cfg->caps |= pause_mask;
>> +
>> +       return 0;
>> +}
>> +
>> +/**
>> + * ixgbe_setup_fc_e610 - Set up flow control
>> + * @hw: pointer to hardware structure
>> + *
>> + * Set up flow control. This has to be done during init time.
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_setup_fc_e610(struct ixgbe_hw *hw)
>> +{
>> +       struct ixgbe_aci_cmd_get_phy_caps_data pcaps = { 0 };
>> +       struct ixgbe_aci_cmd_set_phy_cfg_data cfg = { 0 };
>> +       int err;
>> +
>> +       /* Get the current PHY config */
>> +       err = ixgbe_aci_get_phy_caps(hw, false,
>> +                                    IXGBE_ACI_REPORT_ACTIVE_CFG, &pcaps);
>> +       if (err)
>> +               return err;
>> +
>> +       ixgbe_copy_phy_caps_to_cfg(&pcaps, &cfg);
>> +
>> +       /* Configure the set PHY data */
>> +       err = ixgbe_cfg_phy_fc(hw, &cfg, hw->fc.requested_mode);
>> +       if (err)
>> +               return err;
>> +
>> +       /* If the capabilities have changed, then set the new config */
>> +       if (cfg.caps != pcaps.caps) {
>> +               cfg.caps |= IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT;
>> +
>> +               err = ixgbe_aci_set_phy_cfg(hw, &cfg);
>> +               if (err)
>> +                       return err;
>> +       }
>> +
>> +       return err;
>> +}
>> +
>> +/**
>> + * ixgbe_fc_autoneg_e610 - Configure flow control
>> + * @hw: pointer to hardware structure
>> + *
>> + * Configure Flow Control.
>> + */
>> +void ixgbe_fc_autoneg_e610(struct ixgbe_hw *hw)
>> +{
>> +       int err;
>> +
>> +       /* Get current link err.
>> +        * Current FC mode will be stored in the hw context.
>> +        */
>> +       err = ixgbe_aci_get_link_info(hw, false, NULL);
>> +       if (err)
>> +               goto no_autoneg;
>> +
>> +       /* Check if the link is up */
>> +       if (!(hw->link.link_info.link_info & IXGBE_ACI_LINK_UP))
>> +               goto no_autoneg;
>> +
>> +       /* Check if auto-negotiation has completed */
>> +       if (!(hw->link.link_info.an_info & IXGBE_ACI_AN_COMPLETED))
>> +               goto no_autoneg;
>> +
>> +       hw->fc.fc_was_autonegged = true;
>> +       return;
>> +
>> +no_autoneg:
>> +       hw->fc.fc_was_autonegged = false;
>> +       hw->fc.current_mode = hw->fc.requested_mode;
>> +}
>> +
>> +/**
>> + * ixgbe_disable_rx_e610 - Disable RX unit
>> + * @hw: pointer to hardware structure
>> + *
>> + * Disable RX DMA unit on E610 with use of ACI command (0x000C).
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +void ixgbe_disable_rx_e610(struct ixgbe_hw *hw)
>> +{
>> +       u32 rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
>> +       u32 pfdtxgswc;
>> +       int err;
>> +
>> +       if (!(rxctrl & IXGBE_RXCTRL_RXEN))
>> +               return;
>> +
>> +       pfdtxgswc = IXGBE_READ_REG(hw, IXGBE_PFDTXGSWC);
>> +       if (pfdtxgswc & IXGBE_PFDTXGSWC_VT_LBEN) {
>> +               pfdtxgswc &= ~IXGBE_PFDTXGSWC_VT_LBEN;
>> +               IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, pfdtxgswc);
>> +               hw->mac.set_lben = true;
>> +       } else {
>> +               hw->mac.set_lben = false;
>> +       }
>> +
>> +       err = ixgbe_aci_disable_rxen(hw);
>> +
>> +       /* If we fail - disable RX using register write */
>> +       if (err) {
>> +               rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
>> +               if (rxctrl & IXGBE_RXCTRL_RXEN) {
>> +                       rxctrl &= ~IXGBE_RXCTRL_RXEN;
>> +                       IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl);
>> +               }
>> +       }
>> +}
>> +
>> +/**
>> + * ixgbe_init_phy_ops_e610 - PHY specific init
>> + * @hw: pointer to hardware structure
>> + *
>> + * Initialize any function pointers that were not able to be
>> + * set during init_shared_code because the PHY type was not known.
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_init_phy_ops_e610(struct ixgbe_hw *hw)
>> +{
>> +       struct ixgbe_mac_info *mac = &hw->mac;
>> +       struct ixgbe_phy_info *phy = &hw->phy;
>> +       int ret_val;
>> +
>> +       if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper)
>> +               phy->ops.set_phy_power = ixgbe_set_phy_power_e610;
>> +       else
>> +               phy->ops.set_phy_power = NULL;
>> +
>> +       /* Identify the PHY */
>> +       ret_val = phy->ops.identify(hw);
>[Kalesh] You can change it to:
>return phy->ops.identify(hw);
Will do.

>> +       if (ret_val)
>> +               return ret_val;
>> +
>> +       return ret_val;
>> +}
>> +
>> +/**
>> + * ixgbe_identify_phy_e610 - Identify PHY
>> + * @hw: pointer to hardware structure
>> + *
>> + * Determine PHY type, supported speeds and PHY ID.
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_identify_phy_e610(struct ixgbe_hw *hw)
>> +{
>> +       struct ixgbe_aci_cmd_get_phy_caps_data pcaps;
>> +       int err;
>> +
>> +       /* Set PHY type */
>> +       hw->phy.type = ixgbe_phy_fw;
>> +
>> +       err = ixgbe_aci_get_phy_caps(hw, false,
>> +                                    IXGBE_ACI_REPORT_TOPO_CAP_MEDIA, &pcaps);
>> +       if (err)
>> +               return err;
>> +
>> +       if (!(pcaps.module_compliance_enforcement &
>> +             IXGBE_ACI_MOD_ENFORCE_STRICT_MODE)) {
>> +               /* Handle lenient mode */
>> +               err = ixgbe_aci_get_phy_caps(hw, false,
>> +                                            IXGBE_ACI_REPORT_TOPO_CAP_NO_MEDIA,
>> +                                            &pcaps);
>> +               if (err)
>> +                       return err;
>> +       }
>> +
>> +       /* Determine supported speeds */
>> +       hw->phy.speeds_supported = IXGBE_LINK_SPEED_UNKNOWN;
>> +
>> +       if (pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_10BASE_T ||
>> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_10M_SGMII)
>> +               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_10_FULL;
>> +       if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_100BASE_TX ||
>> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_100M_SGMII ||
>> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_100M_USXGMII)
>> +               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_100_FULL;
>> +       if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_T  ||
>> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_SX ||
>> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_LX ||
>> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_KX ||
>> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1G_SGMII    ||
>> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_1G_USXGMII)
>> +               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_1GB_FULL;
>> +       if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_T       ||
>> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10G_SFI_DA      ||
>> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_SR      ||
>> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_LR      ||
>> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_KR_CR1  ||
>> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10G_SFI_AOC_ACC ||
>> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10G_SFI_C2C     ||
>> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_10G_USXGMII)
>> +               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_10GB_FULL;
>> +
>> +       /* 2.5 and 5 Gbps link speeds must be excluded from the
>> +        * auto-negotiation set used during driver initialization due to
>> +        * compatibility issues with certain switches. Those issues do not
>> +        * exist in case of E610 2.5G SKU device (0x57b1).
>> +        */
>> +       if (!hw->phy.autoneg_advertised &&
>> +           hw->device_id != IXGBE_DEV_ID_E610_2_5G_T)
>> +               hw->phy.autoneg_advertised = hw->phy.speeds_supported;//PK
>> +
>> +       if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_2500BASE_T   ||
>> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_2500BASE_X   ||
>> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_2500BASE_KX  ||
>> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_2500M_SGMII ||
>> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_2500M_USXGMII)
>> +               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_2_5GB_FULL;
>> +
>> +       if (!hw->phy.autoneg_advertised &&
>> +           hw->device_id == IXGBE_DEV_ID_E610_2_5G_T)
>> +               hw->phy.autoneg_advertised = hw->phy.speeds_supported;//PK
>> +
>> +       if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_5GBASE_T  ||
>> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_5GBASE_KR ||
>> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_5G_USXGMII)
>> +               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_5GB_FULL;
>> +
>> +       /* Set PHY ID */
>> +       memcpy(&hw->phy.id, pcaps.phy_id_oui, sizeof(u32));
>> +
>> +       hw->phy.eee_speeds_supported = IXGBE_LINK_SPEED_10_FULL |
>> +                                      IXGBE_LINK_SPEED_100_FULL |
>> +                                      IXGBE_LINK_SPEED_1GB_FULL;
>> +       hw->phy.eee_speeds_advertised = hw->phy.eee_speeds_supported;
>> +
>> +       return 0;
>> +}
>> +
>> +/**
>> + * ixgbe_identify_module_e610 - Identify SFP module type
>> + * @hw: pointer to hardware structure
>> + *
>> + * Identify the SFP module type.
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_identify_module_e610(struct ixgbe_hw *hw)
>> +{
>> +       bool media_available;
>> +       u8 module_type;
>> +       int err;
>> +
>> +       err = ixgbe_update_link_info(hw);
>> +       if (err)
>> +               return err;
>> +
>> +       media_available =
>> +               (hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE);
>> +
>> +       if (media_available) {
>> +               hw->phy.sfp_type = ixgbe_sfp_type_unknown;
>> +
>> +               /* Get module type from hw context updated by
>> +                * ixgbe_update_link_info()
>> +                */
>> +               module_type = hw->link.link_info.module_type[IXGBE_ACI_MOD_TYPE_IDENT];
>> +
>> +               if ((module_type & IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_PASSIVE) ||
>> +                   (module_type & IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_ACTIVE)) {
>> +                       hw->phy.sfp_type = ixgbe_sfp_type_da_cu;
>> +               } else if (module_type & IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_SR) {
>> +                       hw->phy.sfp_type = ixgbe_sfp_type_sr;
>> +               } else if ((module_type & IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_LR) ||
>> +                          (module_type & IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_LRM)) {
>> +                       hw->phy.sfp_type = ixgbe_sfp_type_lr;
>> +               }
>> +       } else {
>> +               hw->phy.sfp_type = ixgbe_sfp_type_not_present;
>> +               return -ENOENT;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +/**
>> + * ixgbe_setup_phy_link_e610 - Sets up firmware-controlled PHYs
>> + * @hw: pointer to hardware structure
>> + *
>> + * Set the parameters for the firmware-controlled PHYs.
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_setup_phy_link_e610(struct ixgbe_hw *hw)
>> +{
>> +       struct ixgbe_aci_cmd_get_phy_caps_data pcaps;
>> +       struct ixgbe_aci_cmd_set_phy_cfg_data pcfg;
>> +       u8 rmode = IXGBE_ACI_REPORT_TOPO_CAP_MEDIA;
>> +       u64 sup_phy_type_low, sup_phy_type_high;
>> +       int err;
>> +
>> +       err = ixgbe_aci_get_link_info(hw, false, NULL);
>> +       if (err)
>> +               return err;
>> +
>> +       /* If media is not available get default config. */
>> +       if (!(hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE))
>> +               rmode = IXGBE_ACI_REPORT_DFLT_CFG;
>> +
>> +       err = ixgbe_aci_get_phy_caps(hw, false, rmode, &pcaps);
>> +       if (err)
>> +               return err;
>> +
>> +       sup_phy_type_low = pcaps.phy_type_low;
>> +       sup_phy_type_high = pcaps.phy_type_high;
>> +
>> +       /* Get Active configuration to avoid unintended changes. */
>> +       err = ixgbe_aci_get_phy_caps(hw, false, IXGBE_ACI_REPORT_ACTIVE_CFG,
>> +                                    &pcaps);
>> +       if (err)
>> +               return err;
>> +
>> +       ixgbe_copy_phy_caps_to_cfg(&pcaps, &pcfg);
>> +
>> +       /* Set default PHY types for a given speed */
>> +       pcfg.phy_type_low = 0;
>> +       pcfg.phy_type_high = 0;
>> +
>> +       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10_FULL) {
>> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_10BASE_T;
>> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_10M_SGMII;
>> +       }
>> +       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) {
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_100BASE_TX;
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_100M_SGMII;
>> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_100M_USXGMII;
>> +       }
>> +       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) {
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_T;
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_SX;
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_LX;
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_KX;
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1G_SGMII;
>> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_1G_USXGMII;
>> +       }
>> +       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_2_5GB_FULL) {
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_2500BASE_T;
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_2500BASE_X;
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_2500BASE_KX;
>> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_2500M_SGMII;
>> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_2500M_USXGMII;
>> +       }
>> +       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_5GB_FULL) {
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_5GBASE_T;
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_5GBASE_KR;
>> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_5G_USXGMII;
>> +       }
>> +       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) {
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_T;
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10G_SFI_DA;
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_SR;
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_LR;
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_KR_CR1;
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10G_SFI_AOC_ACC;
>> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10G_SFI_C2C;
>> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_10G_USXGMII;
>> +       }
>> +
>> +       /* Mask the set values to avoid requesting unsupported link types */
>> +       pcfg.phy_type_low &= sup_phy_type_low;
>> +       pcfg.phy_type_high &= sup_phy_type_high;
>> +
>> +       if (pcfg.phy_type_high != pcaps.phy_type_high ||
>> +           pcfg.phy_type_low != pcaps.phy_type_low ||
>> +           pcfg.caps != pcaps.caps) {
>> +               pcfg.caps |= IXGBE_ACI_PHY_ENA_LINK;
>> +               pcfg.caps |= IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT;
>> +
>> +               err = ixgbe_aci_set_phy_cfg(hw, &pcfg);
>> +               if (err)
>> +                       return err;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +/**
>> + * ixgbe_set_phy_power_e610 - Control power for copper PHY
>> + * @hw: pointer to hardware structure
>> + * @on: true for on, false for off
>> + *
>> + * Set the power on/off of the PHY
>> + * by getting its capabilities and setting the appropriate
>> + * configuration parameters.
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_set_phy_power_e610(struct ixgbe_hw *hw, bool on)
>> +{
>> +       struct ixgbe_aci_cmd_get_phy_caps_data phy_caps = { 0 };
>> +       struct ixgbe_aci_cmd_set_phy_cfg_data phy_cfg = { 0 };
>> +       int err;
>> +
>> +       err = ixgbe_aci_get_phy_caps(hw, false,
>> +                                    IXGBE_ACI_REPORT_ACTIVE_CFG,
>> +                                    &phy_caps);
>> +       if (err)
>> +               return err;
>> +
>> +       ixgbe_copy_phy_caps_to_cfg(&phy_caps, &phy_cfg);
>> +
>> +       if (on)
>> +               phy_cfg.caps &= ~IXGBE_ACI_PHY_ENA_LOW_POWER;
>> +       else
>> +               phy_cfg.caps |= IXGBE_ACI_PHY_ENA_LOW_POWER;
>> +
>> +       /* PHY is already in requested power mode. */
>> +       if (phy_caps.caps == phy_cfg.caps)
>> +               return 0;
>> +
>> +       phy_cfg.caps |= IXGBE_ACI_PHY_ENA_LINK;
>> +       phy_cfg.caps |= IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT;
>> +
>> +       err = ixgbe_aci_set_phy_cfg(hw, &phy_cfg);
>[Kalesh] Change it as:
>return  ixgbe_aci_set_phy_cfg(hw, &phy_cfg);
Will do.

>> +
>> +       return err;
>> +}
>> +
>> +/**
>> + * ixgbe_enter_lplu_e610 - Transition to low power states
>> + * @hw: pointer to hardware structure
>> + *
>> + * Configures Low Power Link Up on transition to low power states
>> + * (from D0 to non-D0). Link is required to enter LPLU so avoid resetting the
>> + * X557 PHY immediately prior to entering LPLU.
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_enter_lplu_e610(struct ixgbe_hw *hw)
>> +{
>> +       struct ixgbe_aci_cmd_get_phy_caps_data phy_caps = { 0 };
>> +       struct ixgbe_aci_cmd_set_phy_cfg_data phy_cfg = { 0 };
>> +       int err;
>> +
>> +       err = ixgbe_aci_get_phy_caps(hw, false,
>> +                                    IXGBE_ACI_REPORT_ACTIVE_CFG,
>> +                                    &phy_caps);
>> +       if (err)
>> +               return err;
>> +
>> +       ixgbe_copy_phy_caps_to_cfg(&phy_caps, &phy_cfg);
>> +
>> +       phy_cfg.low_power_ctrl_an |= IXGBE_ACI_PHY_EN_D3COLD_LOW_POWER_AUTONEG;
>> +
>> +       err = ixgbe_aci_set_phy_cfg(hw, &phy_cfg);
>[Kalesh] Same comment as above
Will do.

>> +
>> +       return err;
>> +}
>> +
>> +/**
>> + * ixgbe_aci_get_netlist_node - get a node handle
>> + * @hw: pointer to the hw struct
>> + * @cmd: get_link_topo AQ structure
>> + * @node_part_number: output node part number if node found
>> + * @node_handle: output node handle parameter if node found
>> + *
>> + * Get the netlist node and assigns it to
>> + * the provided handle using ACI command (0x06E0).
>> + *
>> + * Return: the exit code of the operation.
>> + */
>> +int ixgbe_aci_get_netlist_node(struct ixgbe_hw *hw,
>> +                              struct ixgbe_aci_cmd_get_link_topo *cmd,
>> +                              u8 *node_part_number, u16 *node_handle)
>> +{
>> +       struct ixgbe_aci_desc desc;
>> +
>> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_link_topo);
>> +       desc.params.get_link_topo = *cmd;
>> +
>> +       if (ixgbe_aci_send_cmd(hw, &desc, NULL, 0))
>> +               return -EOPNOTSUPP;
>> +
>> +       if (node_handle)
>> +               *node_handle = desc.params.get_link_topo.addr.handle;
>> +       if (node_part_number)
>> +               *node_part_number = desc.params.get_link_topo.node_part_num;
>> +
>> +       return 0;
>> +}
>> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
>> index 5c5a676..4a4f969 100644
>> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
>> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
>> @@ -27,5 +27,37 @@ int ixgbe_aci_get_phy_caps(struct ixgbe_hw *hw, bool qual_mods, u8 report_mode,
>>                            struct ixgbe_aci_cmd_get_phy_caps_data *pcaps);
>>  void ixgbe_copy_phy_caps_to_cfg(struct ixgbe_aci_cmd_get_phy_caps_data *caps,
>>                                 struct ixgbe_aci_cmd_set_phy_cfg_data *cfg);
>> +int ixgbe_aci_set_phy_cfg(struct ixgbe_hw *hw,
>> +                         struct ixgbe_aci_cmd_set_phy_cfg_data *cfg);
>> +int ixgbe_aci_set_link_restart_an(struct ixgbe_hw *hw, bool ena_link);
>> +int ixgbe_update_link_info(struct ixgbe_hw *hw);
>> +int ixgbe_get_link_status(struct ixgbe_hw *hw, bool *link_up);
>> +int ixgbe_aci_get_link_info(struct ixgbe_hw *hw, bool ena_lse,
>> +                           struct ixgbe_link_status *link);
>> +int ixgbe_aci_set_event_mask(struct ixgbe_hw *hw, u8 port_num, u16 mask);
>> +int ixgbe_configure_lse(struct ixgbe_hw *hw, bool activate, u16 mask);
>> +enum ixgbe_media_type ixgbe_get_media_type_e610(struct ixgbe_hw *hw);
>> +int ixgbe_setup_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed speed,
>> +                         bool autoneg_wait);
>> +int ixgbe_check_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
>> +                         bool *link_up, bool link_up_wait_to_complete);
>> +int ixgbe_get_link_capabilities_e610(struct ixgbe_hw *hw,
>> +                                    ixgbe_link_speed *speed,
>> +                                    bool *autoneg);
>> +int ixgbe_cfg_phy_fc(struct ixgbe_hw *hw,
>> +                    struct ixgbe_aci_cmd_set_phy_cfg_data *cfg,
>> +                    enum ixgbe_fc_mode req_mode);
>> +int ixgbe_setup_fc_e610(struct ixgbe_hw *hw);
>> +void ixgbe_fc_autoneg_e610(struct ixgbe_hw *hw);
>> +void ixgbe_disable_rx_e610(struct ixgbe_hw *hw);
>> +int ixgbe_init_phy_ops_e610(struct ixgbe_hw *hw);
>> +int ixgbe_identify_phy_e610(struct ixgbe_hw *hw);
>> +int ixgbe_identify_module_e610(struct ixgbe_hw *hw);
>> +int ixgbe_setup_phy_link_e610(struct ixgbe_hw *hw);
>> +int ixgbe_set_phy_power_e610(struct ixgbe_hw *hw, bool on);
>> +int ixgbe_enter_lplu_e610(struct ixgbe_hw *hw);
>> +int ixgbe_aci_get_netlist_node(struct ixgbe_hw *hw,
>> +                              struct ixgbe_aci_cmd_get_link_topo *cmd,
>> +                              u8 *node_part_number, u16 *node_handle);
>>
>>  #endif /* _IXGBE_E610_H_ */
>> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
>> index 6c6d990..1f97652 100644
>> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
>> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
>> @@ -652,6 +652,7 @@ struct ixgbe_aci_cmd_link_topo_params {
>>  #define IXGBE_ACI_LINK_TOPO_NODE_TYPE_CLK_MUX  10
>>  #define IXGBE_ACI_LINK_TOPO_NODE_TYPE_GPS      11
>>  #define IXGBE_ACI_LINK_TOPO_NODE_CTX_S         4
>> +#define IXGBE_ACI_LINK_TOPO_NODE_CTX_M         GENMASK(7, 4)
>>  #define IXGBE_ACI_LINK_TOPO_NODE_CTX_GLOBAL                    0
>>  #define IXGBE_ACI_LINK_TOPO_NODE_CTX_BOARD                     1
>>  #define IXGBE_ACI_LINK_TOPO_NODE_CTX_PORT                      2
>> --
>> 2.43.0
>>
>>
>
>
>-- 
>Regards,
>Kalesh A P
Thank you All for review.
Piotr

^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: [PATCH iwl-next v9 2/7] ixgbe: Add support for E610 device capabilities detection
  2024-10-18  3:06   ` Kalesh Anakkur Purayil
  2024-10-21  8:42     ` Kwapulinski, Piotr
@ 2024-10-23 12:27     ` Kwapulinski, Piotr
  1 sibling, 0 replies; 16+ messages in thread
From: Kwapulinski, Piotr @ 2024-10-23 12:27 UTC (permalink / raw)
  To: Kalesh Anakkur Purayil
  Cc: intel-wired-lan@lists.osuosl.org, netdev@vger.kernel.org,
	Wegrzyn, Stefan, Jagielski, Jedrzej, Sokolowski, Jan

>-----Original Message-----
>From: Kalesh Anakkur Purayil <kalesh-anakkur.purayil@broadcom.com> 
>Sent: Friday, October 18, 2024 5:06 AM
>To: Kwapulinski, Piotr <piotr.kwapulinski@intel.com>
>Cc: intel-wired-lan@lists.osuosl.org; netdev@vger.kernel.org; Wegrzyn, Stefan <stefan.wegrzyn@intel.com>; Jagielski, Jedrzej <jedrzej.jagielski@intel.com>; Sokolowski, Jan <jan.sokolowski@intel.com>
>Subject: Re: [PATCH iwl-next v9 2/7] ixgbe: Add support for E610 device capabilities detection
>
>On Thu, Oct 3, 2024 at 7:48 PM Piotr Kwapulinski
><piotr.kwapulinski@intel.com> wrote:
>>
>> Add low level support for E610 device capabilities detection. The
>> capabilities are discovered via the Admin Command Interface. Discover the
>> following capabilities:
>> - function caps: vmdq, dcb, rss, rx/tx qs, msix, nvm, orom, reset
>> - device caps: vsi, fdir, 1588
>> - phy caps
>>
>> Co-developed-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
>> Signed-off-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
>> Co-developed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
>> Signed-off-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
>> Reviewed-by: Jan Sokolowski <jan.sokolowski@intel.com>
>> Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>
>
>Hi Piotr,
>
>Some minor cosmetic comments in line.
>
>> ---
>>  drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 540 ++++++++++++++++++
>>  drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h |  12 +
>>  drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |   8 +
>>  3 files changed, 560 insertions(+)
>>
>> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
>> index 28bd7da..3bc88df 100644
>> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
>> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
>> @@ -493,3 +493,543 @@ void ixgbe_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res)
>>                 total_delay++;
>>         }
>>  }
>> +
>> +/**
>> + * ixgbe_parse_e610_caps - Parse common device/function capabilities
>> + * @hw: pointer to the HW struct
>> + * @caps: pointer to common capabilities structure
>> + * @elem: the capability element to parse
>> + * @prefix: message prefix for tracing capabilities
>> + *
>> + * Given a capability element, extract relevant details into the common
>> + * capability structure.
>> + *
>> + * Return: true if the capability matches one of the common capability ids,
>> + * false otherwise.
>> + */
>> +static bool ixgbe_parse_e610_caps(struct ixgbe_hw *hw,
>> +                                 struct ixgbe_hw_caps *caps,
>> +                                 struct ixgbe_aci_cmd_list_caps_elem *elem,
>> +                                 const char *prefix)
>> +{
>> +       u32 logical_id = elem->logical_id;
>> +       u32 phys_id = elem->phys_id;
>> +       u32 number = elem->number;
>> +       u16 cap = elem->cap;
>> +
>> +       switch (cap) {
>> +       case IXGBE_ACI_CAPS_VALID_FUNCTIONS:
>> +               caps->valid_functions = number;
>> +               break;
>> +       case IXGBE_ACI_CAPS_SRIOV:
>> +               caps->sr_iov_1_1 = (number == 1);
>> +               break;
>> +       case IXGBE_ACI_CAPS_VMDQ:
>> +               caps->vmdq = (number == 1);
>> +               break;
>> +       case IXGBE_ACI_CAPS_DCB:
>> +               caps->dcb = (number == 1);
>> +               caps->active_tc_bitmap = logical_id;
>> +               caps->maxtc = phys_id;
>> +               break;
>> +       case IXGBE_ACI_CAPS_RSS:
>> +               caps->rss_table_size = number;
>> +               caps->rss_table_entry_width = logical_id;
>> +               break;
>> +       case IXGBE_ACI_CAPS_RXQS:
>> +               caps->num_rxq = number;
>> +               caps->rxq_first_id = phys_id;
>> +               break;
>> +       case IXGBE_ACI_CAPS_TXQS:
>> +               caps->num_txq = number;
>> +               caps->txq_first_id = phys_id;
>> +               break;
>> +       case IXGBE_ACI_CAPS_MSIX:
>> +               caps->num_msix_vectors = number;
>> +               caps->msix_vector_first_id = phys_id;
>> +               break;
>> +       case IXGBE_ACI_CAPS_NVM_VER:
>> +               break;
>> +       case IXGBE_ACI_CAPS_MAX_MTU:
>> +               caps->max_mtu = number;
>> +               break;
>> +       case IXGBE_ACI_CAPS_PCIE_RESET_AVOIDANCE:
>> +               caps->pcie_reset_avoidance = (number > 0);
>> +               break;
>> +       case IXGBE_ACI_CAPS_POST_UPDATE_RESET_RESTRICT:
>> +               caps->reset_restrict_support = (number == 1);
>> +               break;
>> +       case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG0:
>> +       case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG1:
>> +       case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG2:
>> +       case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG3:
>> +       {
>> +               u8 index = cap - IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG0;
>> +
>> +               caps->ext_topo_dev_img_ver_high[index] = number;
>> +               caps->ext_topo_dev_img_ver_low[index] = logical_id;
>> +               caps->ext_topo_dev_img_part_num[index] =
>> +                       FIELD_GET(IXGBE_EXT_TOPO_DEV_IMG_PART_NUM_M, phys_id);
>> +               caps->ext_topo_dev_img_load_en[index] =
>> +                       (phys_id & IXGBE_EXT_TOPO_DEV_IMG_LOAD_EN) != 0;
>> +               caps->ext_topo_dev_img_prog_en[index] =
>> +                       (phys_id & IXGBE_EXT_TOPO_DEV_IMG_PROG_EN) != 0;
>> +               break;
>> +       }
>> +       default:
>> +               /* Not one of the recognized common capabilities */
>> +               return false;
>> +       }
>> +
>> +       return true;
>> +}
>> +
>> +/**
>> + * ixgbe_parse_valid_functions_cap - Parse IXGBE_ACI_CAPS_VALID_FUNCTIONS caps
>> + * @hw: pointer to the HW struct
>> + * @dev_p: pointer to device capabilities structure
>> + * @cap: capability element to parse
>> + *
>> + * Parse IXGBE_ACI_CAPS_VALID_FUNCTIONS for device capabilities.
>> + */
>> +static void
>> +ixgbe_parse_valid_functions_cap(struct ixgbe_hw *hw,
>> +                               struct ixgbe_hw_dev_caps *dev_p,
>> +                               struct ixgbe_aci_cmd_list_caps_elem *cap)
>> +{
>> +       u32 number = cap->number;
>[Kalesh] Do you really need a local variable here? Same comment
>applies to functions below as well.
>> +
>> +       dev_p->num_funcs = hweight32(number);
>> +}
>> +
>> +/**
>> + * ixgbe_parse_vf_dev_caps - Parse IXGBE_ACI_CAPS_VF device caps
>> + * @hw: pointer to the HW struct
>> + * @dev_p: pointer to device capabilities structure
>> + * @cap: capability element to parse
>> + *
>> + * Parse IXGBE_ACI_CAPS_VF for device capabilities.
>> + */
>> +static void ixgbe_parse_vf_dev_caps(struct ixgbe_hw *hw,
>> +                                   struct ixgbe_hw_dev_caps *dev_p,
>> +                                   struct ixgbe_aci_cmd_list_caps_elem *cap)
>> +{
>> +       u32 number = cap->number;
>> +
>> +       dev_p->num_vfs_exposed = number;
>> +}
>> +
>> +/**
>> + * ixgbe_parse_vsi_dev_caps - Parse IXGBE_ACI_CAPS_VSI device caps
>> + * @hw: pointer to the HW struct
>> + * @dev_p: pointer to device capabilities structure
>> + * @cap: capability element to parse
>> + *
>> + * Parse IXGBE_ACI_CAPS_VSI for device capabilities.
>> + */
>> +static void ixgbe_parse_vsi_dev_caps(struct ixgbe_hw *hw,
>> +                                    struct ixgbe_hw_dev_caps *dev_p,
>> +                                    struct ixgbe_aci_cmd_list_caps_elem *cap)
>> +{
>> +       u32 number = cap->number;
>> +
>> +       dev_p->num_vsi_allocd_to_host = number;
>> +}
>> +
>> +/**
>> + * ixgbe_parse_fdir_dev_caps - Parse IXGBE_ACI_CAPS_FD device caps
>> + * @hw: pointer to the HW struct
>> + * @dev_p: pointer to device capabilities structure
>> + * @cap: capability element to parse
>> + *
>> + * Parse IXGBE_ACI_CAPS_FD for device capabilities.
>> + */
>> +static void ixgbe_parse_fdir_dev_caps(struct ixgbe_hw *hw,
>> +                                     struct ixgbe_hw_dev_caps *dev_p,
>> +                                     struct ixgbe_aci_cmd_list_caps_elem *cap)
>> +{
>> +       u32 number = cap->number;
>> +
>> +       dev_p->num_flow_director_fltr = number;
>> +}
>> +
>> +/**
>> + * ixgbe_parse_dev_caps - Parse device capabilities
>> + * @hw: pointer to the HW struct
>> + * @dev_p: pointer to device capabilities structure
>> + * @buf: buffer containing the device capability records
>> + * @cap_count: the number of capabilities
>> + *
>> + * Helper device to parse device (0x000B) capabilities list. For
>> + * capabilities shared between device and function, this relies on
>> + * ixgbe_parse_e610_caps.
>> + *
>> + * Loop through the list of provided capabilities and extract the relevant
>> + * data into the device capabilities structured.
>> + */
>> +static void ixgbe_parse_dev_caps(struct ixgbe_hw *hw,
>> +                                struct ixgbe_hw_dev_caps *dev_p,
>> +                                void *buf, u32 cap_count)
>> +{
>> +       struct ixgbe_aci_cmd_list_caps_elem *cap_resp;
>> +       u32 i;
>> +
>> +       cap_resp = (struct ixgbe_aci_cmd_list_caps_elem *)buf;
>> +
>> +       memset(dev_p, 0, sizeof(*dev_p));
>> +
>> +       for (i = 0; i < cap_count; i++) {
>> +               u16 cap = cap_resp[i].cap;
>> +
>> +               ixgbe_parse_e610_caps(hw, &dev_p->common_cap, &cap_resp[i],
>> +                                     "dev caps");
>> +
>> +               switch (cap) {
>> +               case IXGBE_ACI_CAPS_VALID_FUNCTIONS:
>> +                       ixgbe_parse_valid_functions_cap(hw, dev_p,
>> +                                                       &cap_resp[i]);
>> +                       break;
>> +               case IXGBE_ACI_CAPS_VF:
>> +                       ixgbe_parse_vf_dev_caps(hw, dev_p, &cap_resp[i]);
>> +                       break;
>> +               case IXGBE_ACI_CAPS_VSI:
>> +                       ixgbe_parse_vsi_dev_caps(hw, dev_p, &cap_resp[i]);
>> +                       break;
>> +               case  IXGBE_ACI_CAPS_FD:
>> +                       ixgbe_parse_fdir_dev_caps(hw, dev_p, &cap_resp[i]);
>> +                       break;
>> +               default:
>> +                       /* Don't list common capabilities as unknown */
>> +                       break;
>> +               }
>> +       }
>> +}
>> +
>> +/**
>> + * ixgbe_parse_vf_func_caps - Parse IXGBE_ACI_CAPS_VF function caps
>> + * @hw: pointer to the HW struct
>> + * @func_p: pointer to function capabilities structure
>> + * @cap: pointer to the capability element to parse
>> + *
>> + * Extract function capabilities for IXGBE_ACI_CAPS_VF.
>> + */
>> +static void ixgbe_parse_vf_func_caps(struct ixgbe_hw *hw,
>> +                                    struct ixgbe_hw_func_caps *func_p,
>> +                                    struct ixgbe_aci_cmd_list_caps_elem *cap)
>> +{
>> +       u32 logical_id = cap->logical_id;
>> +       u32 number = cap->number;
>> +
>> +       func_p->num_allocd_vfs = number;
>> +       func_p->vf_base_id = logical_id;
>> +}
>> +
>> +/**
>> + * ixgbe_get_num_per_func - determine number of resources per PF
>> + * @hw: pointer to the HW structure
>> + * @max: value to be evenly split between each PF
>> + *
>> + * Determine the number of valid functions by going through the bitmap returned
>> + * from parsing capabilities and use this to calculate the number of resources
>> + * per PF based on the max value passed in.
>> + *
>> + * Return: the number of resources per PF or 0, if no PH are available.
>> + */
>> +static u32 ixgbe_get_num_per_func(struct ixgbe_hw *hw, u32 max)
>> +{
>> +#define IXGBE_CAPS_VALID_FUNCS_M       GENMASK(7, 0)
>> +       u8 funcs = hweight8(hw->dev_caps.common_cap.valid_functions &
>> +                           IXGBE_CAPS_VALID_FUNCS_M);
>> +
>> +       return funcs ? (max / funcs) : 0;
>> +}
>> +
>> +/**
>> + * ixgbe_parse_vsi_func_caps - Parse IXGBE_ACI_CAPS_VSI function caps
>> + * @hw: pointer to the HW struct
>> + * @func_p: pointer to function capabilities structure
>> + * @cap: pointer to the capability element to parse
>> + *
>> + * Extract function capabilities for IXGBE_ACI_CAPS_VSI.
>> + */
>> +static void ixgbe_parse_vsi_func_caps(struct ixgbe_hw *hw,
>> +                                     struct ixgbe_hw_func_caps *func_p,
>> +                                     struct ixgbe_aci_cmd_list_caps_elem *cap)
>> +{
>> +       func_p->guar_num_vsi = ixgbe_get_num_per_func(hw, IXGBE_MAX_VSI);
>> +}
>> +
>> +/**
>> + * ixgbe_parse_func_caps - Parse function capabilities
>> + * @hw: pointer to the HW struct
>> + * @func_p: pointer to function capabilities structure
>> + * @buf: buffer containing the function capability records
>> + * @cap_count: the number of capabilities
>> + *
>> + * Helper function to parse function (0x000A) capabilities list. For
>> + * capabilities shared between device and function, this relies on
>> + * ixgbe_parse_e610_caps.
>> + *
>> + * Loop through the list of provided capabilities and extract the relevant
>> + * data into the function capabilities structured.
>> + */
>> +static void ixgbe_parse_func_caps(struct ixgbe_hw *hw,
>> +                                 struct ixgbe_hw_func_caps *func_p,
>> +                                 void *buf, u32 cap_count)
>> +{
>> +       struct ixgbe_aci_cmd_list_caps_elem *cap_resp;
>> +       u32 i;
>> +
>> +       cap_resp = (struct ixgbe_aci_cmd_list_caps_elem *)buf;
>> +
>> +       memset(func_p, 0, sizeof(*func_p));
>> +
>> +       for (i = 0; i < cap_count; i++) {
>> +               u16 cap = cap_resp[i].cap;
>> +
>> +               ixgbe_parse_e610_caps(hw, &func_p->common_cap,
>> +                                     &cap_resp[i], "func caps");
>> +
>> +               switch (cap) {
>> +               case IXGBE_ACI_CAPS_VF:
>> +                       ixgbe_parse_vf_func_caps(hw, func_p, &cap_resp[i]);
>> +                       break;
>> +               case IXGBE_ACI_CAPS_VSI:
>> +                       ixgbe_parse_vsi_func_caps(hw, func_p, &cap_resp[i]);
>> +                       break;
>> +               default:
>> +                       /* Don't list common capabilities as unknown */
>> +                       break;
>> +               }
>> +       }
>> +}
>> +
>> +/**
>> + * ixgbe_aci_list_caps - query function/device capabilities
>> + * @hw: pointer to the HW struct
>> + * @buf: a buffer to hold the capabilities
>> + * @buf_size: size of the buffer
>> + * @cap_count: if not NULL, set to the number of capabilities reported
>> + * @opc: capabilities type to discover, device or function
>> + *
>> + * Get the function (0x000A) or device (0x000B) capabilities description from
>> + * firmware and store it in the buffer.
>> + *
>> + * If the cap_count pointer is not NULL, then it is set to the number of
>> + * capabilities firmware will report. Note that if the buffer size is too
>> + * small, it is possible the command will return -ENOMEM. The
>> + * cap_count will still be updated in this case. It is recommended that the
>> + * buffer size be set to IXGBE_ACI_MAX_BUFFER_SIZE (the largest possible
>> + * buffer that firmware could return) to avoid this.
>> + *
>> + * Return: the exit code of the operation.
>> + * Exit code of -ENOMEM means the buffer size is too small.
>> + */
>> +int ixgbe_aci_list_caps(struct ixgbe_hw *hw, void *buf, u16 buf_size,
>> +                       u32 *cap_count, enum ixgbe_aci_opc opc)
>> +{
>> +       struct ixgbe_aci_cmd_list_caps *cmd;
>> +       struct ixgbe_aci_desc desc;
>> +       int err;
>> +
>> +       cmd = &desc.params.get_cap;
>> +
>> +       if (opc != ixgbe_aci_opc_list_func_caps &&
>> +           opc != ixgbe_aci_opc_list_dev_caps)
>> +               return -EINVAL;
>> +
>> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, opc);
>> +       err = ixgbe_aci_send_cmd(hw, &desc, buf, buf_size);
>> +
>> +       if (cap_count)
>[Kalesh] Do you need a check for !err as well here?
Thank you for pointing this out - in fact, it is tried/caught by the callers.
Piotr
[...]

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2024-10-23 12:27 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-03 14:16 [PATCH iwl-next v9 0/7] ixgbe: Add support for Intel(R) E610 device Piotr Kwapulinski
2024-10-03 14:16 ` [PATCH iwl-next v9 1/7] ixgbe: Add support for E610 FW Admin Command Interface Piotr Kwapulinski
2024-10-03 14:16 ` [PATCH iwl-next v9 2/7] ixgbe: Add support for E610 device capabilities detection Piotr Kwapulinski
2024-10-17  9:46   ` Simon Horman
2024-10-18  3:06   ` Kalesh Anakkur Purayil
2024-10-21  8:42     ` Kwapulinski, Piotr
2024-10-23 12:27     ` Kwapulinski, Piotr
2024-10-03 14:16 ` [PATCH iwl-next v9 3/7] ixgbe: Add link management support for E610 device Piotr Kwapulinski
2024-10-17  9:46   ` Simon Horman
2024-10-17 13:26   ` Kalesh Anakkur Purayil
2024-10-21  9:01     ` Kwapulinski, Piotr
2024-10-03 14:16 ` [PATCH iwl-next v9 4/7] ixgbe: Add support for NVM handling in " Piotr Kwapulinski
2024-10-03 14:16 ` [PATCH iwl-next v9 5/7] ixgbe: Add ixgbe_x540 multiple header inclusion protection Piotr Kwapulinski
2024-10-17  9:47   ` Simon Horman
2024-10-03 14:16 ` [PATCH iwl-next v9 6/7] ixgbe: Clean up the E610 link management related code Piotr Kwapulinski
2024-10-03 14:16 ` [PATCH iwl-next v9 7/7] ixgbe: Enable link management in E610 device Piotr Kwapulinski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).