From: Ciara Loftus <ciara.loftus@intel.com>
To: dev@dpdk.org
Cc: Mateusz Fryze <mateusz.fryze@intel.com>,
Ciara Loftus <ciara.loftus@intel.com>
Subject: [PATCH 09/10] net/e1000/base: auto-negotiation status for 1000BASE-T
Date: Wed, 20 May 2026 12:52:46 +0000 [thread overview]
Message-ID: <20260520125256.354336-10-ciara.loftus@intel.com> (raw)
In-Reply-To: <20260520125256.354336-1-ciara.loftus@intel.com>
From: Mateusz Fryze <mateusz.fryze@intel.com>
Add functionality to find auto-negotiation status on 1000BASE-T PHYs
based on specific PHY registers.
Signed-off-by: Mateusz Fryze <mateusz.fryze@intel.com>
Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
---
.mailmap | 1 +
drivers/net/intel/e1000/base/e1000_82575.c | 1 +
drivers/net/intel/e1000/base/e1000_api.c | 16 ++++
drivers/net/intel/e1000/base/e1000_api.h | 1 +
drivers/net/intel/e1000/base/e1000_defines.h | 22 ++++++
drivers/net/intel/e1000/base/e1000_hw.h | 9 +++
drivers/net/intel/e1000/base/e1000_phy.c | 81 ++++++++++++++++++++
drivers/net/intel/e1000/base/e1000_phy.h | 2 +
8 files changed, 133 insertions(+)
diff --git a/.mailmap b/.mailmap
index f3130df686..4a211b1211 100644
--- a/.mailmap
+++ b/.mailmap
@@ -1033,6 +1033,7 @@ Masoud Hasanifard <masoudhasanifard@gmail.com>
Masoumeh Farhadi Nia <masoumeh.farhadinia@gmail.com>
Matan Azrad <matan@nvidia.com> <matan@mellanox.com>
Matej Vido <matejvido@gmail.com> <vido@cesnet.cz>
+Mateusz Fryze <mateusz.fryze@intel.com>
Mateusz Kowalski <mateusz.kowalski@intel.com>
Mateusz Pacuszka <mateuszx.pacuszka@intel.com>
Mateusz Polchlopek <mateusz.polchlopek@intel.com>
diff --git a/drivers/net/intel/e1000/base/e1000_82575.c b/drivers/net/intel/e1000/base/e1000_82575.c
index 8ae2b77d5f..a2b563975e 100644
--- a/drivers/net/intel/e1000/base/e1000_82575.c
+++ b/drivers/net/intel/e1000/base/e1000_82575.c
@@ -233,6 +233,7 @@ STATIC s32 e1000_init_phy_params_82575(struct e1000_hw *hw)
phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_82580;
phy->ops.force_speed_duplex =
e1000_phy_force_speed_duplex_82577;
+ phy->ops.get_an_status = e1000_1gbase_t_autoneg_status;
break;
case I210_I_PHY_ID:
phy->type = e1000_phy_i210;
diff --git a/drivers/net/intel/e1000/base/e1000_api.c b/drivers/net/intel/e1000/base/e1000_api.c
index a7877613e3..83b3d6c439 100644
--- a/drivers/net/intel/e1000/base/e1000_api.c
+++ b/drivers/net/intel/e1000/base/e1000_api.c
@@ -1138,6 +1138,22 @@ s32 e1000_get_phy_info(struct e1000_hw *hw)
return E1000_SUCCESS;
}
+/**
+ * e1000_get_an_status - Finds Auto-negotiation status based on PHY registers
+ * @hw: pointer to the HW structure
+ * @an_status: AN status
+ *
+ * This function gets information from the PHY specific registers to determine
+ * Auto-negotiation status.
+ **/
+s32 e1000_get_an_status(struct e1000_hw *hw, u8 *an_status)
+{
+ if (hw->phy.ops.get_an_status)
+ return hw->phy.ops.get_an_status(hw, an_status);
+
+ return E1000_SUCCESS;
+}
+
/**
* e1000_phy_hw_reset - Hard PHY reset
* @hw: pointer to the HW structure
diff --git a/drivers/net/intel/e1000/base/e1000_api.h b/drivers/net/intel/e1000/base/e1000_api.h
index ca3248c214..1f81f49bd5 100644
--- a/drivers/net/intel/e1000/base/e1000_api.h
+++ b/drivers/net/intel/e1000/base/e1000_api.h
@@ -59,6 +59,7 @@ s32 e1000_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data);
s32 e1000_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg, u32 offset,
u8 data);
s32 e1000_get_phy_info(struct e1000_hw *hw);
+s32 e1000_get_an_status(struct e1000_hw *hw, u8 *an_status);
void e1000_release_phy(struct e1000_hw *hw);
s32 e1000_acquire_phy(struct e1000_hw *hw);
s32 e1000_cfg_on_link_up(struct e1000_hw *hw);
diff --git a/drivers/net/intel/e1000/base/e1000_defines.h b/drivers/net/intel/e1000/base/e1000_defines.h
index 6c710300a6..ba12dde770 100644
--- a/drivers/net/intel/e1000/base/e1000_defines.h
+++ b/drivers/net/intel/e1000/base/e1000_defines.h
@@ -1103,6 +1103,28 @@
#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */
+/* PHY Status Register */
+#define PHY_STATUS_LINK_STATUS_SHIFT 2
+#define PHY_STATUS_AN_ABILITY_SHIFT 3
+#define PHY_STATUS_REMOTE_FAULT_SHIFT 4
+#define PHY_STATUS_AN_COMPLETE_SHIFT 5
+#define PHY_STATUS_LINK_STATUS_MASK (0x01 << PHY_STATUS_LINK_STATUS_SHIFT)
+#define PHY_STATUS_AN_ABILITY_MASK (0x01 << PHY_STATUS_AN_ABILITY_SHIFT)
+#define PHY_STATUS_REMOTE_FAULT_MASK (0x01 << PHY_STATUS_REMOTE_FAULT_SHIFT)
+#define PHY_STATUS_AN_COMPLETE_MASK (0x01 << PHY_STATUS_AN_COMPLETE_SHIFT)
+
+/* Auto negotiation Expansion Register */
+#define PHY_AUTONEG_EXP_LP_AN_ABLE_SHIFT 0
+#define PHY_AUTONEG_EXP_PAGE_RECVD_SHIFT 1
+#define PHY_AUTONEG_EXP_NEXT_PAGE_ABLE_SHIFT 2
+#define PHY_AUTONEG_EXP_LP_NEXT_PAGE_ABLE_SHIFT 3
+#define PHY_AUTONEG_EXP_PARALLEL_DETECT_FLT_SHIFT 4
+#define PHY_AUTONEG_EXP_LP_AN_ABLE_MASK (0x01 << PHY_AUTONEG_EXP_LP_AN_ABLE_SHIFT)
+#define PHY_AUTONEG_EXP_PAGE_RECVD_MASK (0x01 << PHY_AUTONEG_EXP_PAGE_RECVD_SHIFT)
+#define PHY_AUTONEG_EXP_NEXT_PAGE_ABLE_MASK (0x01 << PHY_AUTONEG_EXP_NEXT_PAGE_ABLE_SHIFT)
+#define PHY_AUTONEG_EXP_LP_NEXT_PAGE_ABLE_MASK (0x01 << PHY_AUTONEG_EXP_LP_NEXT_PAGE_ABLE_SHIFT)
+#define PHY_AUTONEG_EXP_PARALLEL_DETECT_FLT_MASK (0x01 << PHY_AUTONEG_EXP_PARALLEL_DETECT_FLT_SHIFT)
+
/* PHY GPY 211 registers */
#define STANDARD_AN_REG_MASK 0x0007 /* MMD */
#define ANEG_MULTIGBT_AN_CTRL 0x0020 /* MULTI GBT AN Control Register */
diff --git a/drivers/net/intel/e1000/base/e1000_hw.h b/drivers/net/intel/e1000/base/e1000_hw.h
index 9b1fafd75c..99c2195916 100644
--- a/drivers/net/intel/e1000/base/e1000_hw.h
+++ b/drivers/net/intel/e1000/base/e1000_hw.h
@@ -409,6 +409,14 @@ enum e1000_serdes_link_state {
e1000_serdes_link_forced_up
};
+enum e1000_autoneg_status {
+ e1000_an_off = 0, /* No conn.; AN unsupported, disabled, or disabled on the LP */
+ e1000_an_failed, /* Remote Fault or Parallel Detection Fault reported */
+ e1000_an_in_progress,
+ e1000_an_complete,
+ e1000_an_status_unavailable /* AN status could not be obtained */
+};
+
enum e1000_invm_structure_type {
e1000_invm_uninitialized_structure = 0x00,
e1000_invm_word_autoload_structure = 0x01,
@@ -803,6 +811,7 @@ struct e1000_phy_operations {
s32 (*write_reg_page)(struct e1000_hw *, u32, u16);
void (*power_up)(struct e1000_hw *);
void (*power_down)(struct e1000_hw *);
+ s32 (*get_an_status)(struct e1000_hw *, u8 *);
s32 (*read_i2c_byte)(struct e1000_hw *, u8, u8, u8 *);
s32 (*write_i2c_byte)(struct e1000_hw *, u8, u8, u8);
};
diff --git a/drivers/net/intel/e1000/base/e1000_phy.c b/drivers/net/intel/e1000/base/e1000_phy.c
index 31ef5089ba..c66ae44e7a 100644
--- a/drivers/net/intel/e1000/base/e1000_phy.c
+++ b/drivers/net/intel/e1000/base/e1000_phy.c
@@ -63,6 +63,7 @@ void e1000_init_phy_ops_generic(struct e1000_hw *hw)
phy->ops.write_reg_page = e1000_null_write_reg;
phy->ops.power_up = e1000_null_phy_generic;
phy->ops.power_down = e1000_null_phy_generic;
+ phy->ops.get_an_status = e1000_null_an_status;
phy->ops.read_i2c_byte = e1000_read_i2c_byte_null;
phy->ops.write_i2c_byte = e1000_write_i2c_byte_null;
phy->ops.cfg_on_link_up = e1000_null_ops_generic;
@@ -133,6 +134,21 @@ s32 e1000_null_write_reg(struct e1000_hw E1000_UNUSEDARG *hw,
return E1000_SUCCESS;
}
+/**
+ * e1000_null_link_info - No-op function, return 0
+ * @hw: pointer to the HW structure
+ * @status: dummy variable
+ **/
+s32 e1000_null_an_status(struct e1000_hw E1000_UNUSEDARG *hw,
+ u8 *status)
+{
+ DEBUGFUNC("e1000_null_an_status");
+ UNREFERENCED_1PARAMETER(hw);
+ *status = e1000_an_status_unavailable;
+
+ return E1000_SUCCESS;
+}
+
/**
* e1000_read_i2c_byte_null - No-op function, return 0
* @hw: pointer to hardware structure
@@ -2427,6 +2443,71 @@ STATIC s32 e1000_wait_autoneg(struct e1000_hw *hw)
return ret_val;
}
+/**
+ * e1000_1gbase_t_autoneg_status - Gets information on current AN status.
+ * @hw: pointer to the HW structure
+ * @an_status: pointer to the AN status
+ *
+ * The function finds the Auto-negotiation status of 1000BASE-T PHY based on
+ * the data from PHY Status (PSTATUS) and Auto–Negotiation Expansion (ANE)
+ * PHY registers.
+ *
+ * @note The function will report Auto-negotiation OFF when there is no
+ * media connected to the port. When used during the PHY reset, it might not
+ * report a valid status.
+ **/
+s32 e1000_1gbase_t_autoneg_status(struct e1000_hw *hw, u8 *an_status)
+{
+ s32 ret_val = E1000_SUCCESS;
+ u16 phy_reg = 0;
+
+ DEBUGFUNC("e1000_1gbase_t_autoneg_status\n");
+
+ do {
+ *an_status = e1000_an_status_unavailable;
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_reg);
+ if (ret_val) {
+ DEBUGOUT1("Reading PHY STATUS register returned error: %X\n", ret_val);
+ break;
+ }
+
+ if (!(phy_reg & PHY_STATUS_AN_ABILITY_MASK)) {
+ *an_status = e1000_an_off;
+ break;
+ }
+
+ if (phy_reg & (PHY_STATUS_AN_COMPLETE_MASK | PHY_STATUS_LINK_STATUS_MASK)) {
+ *an_status = e1000_an_complete;
+ break;
+ }
+
+ if (phy_reg & PHY_STATUS_REMOTE_FAULT_MASK) {
+ *an_status = e1000_an_failed;
+ break;
+ }
+
+ ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_reg);
+ if (ret_val) {
+ DEBUGOUT1("Reading PHY ANE register returned error: %X\n", ret_val);
+ break;
+ }
+
+ if (!(phy_reg & PHY_AUTONEG_EXP_LP_AN_ABLE_MASK)) {
+ *an_status = e1000_an_off;
+ break;
+ }
+
+ if (phy_reg & PHY_AUTONEG_EXP_PARALLEL_DETECT_FLT_MASK) {
+ *an_status = e1000_an_failed;
+ break;
+ }
+
+ *an_status = e1000_an_in_progress;
+ } while (0);
+
+ return ret_val;
+}
+
/**
* e1000_phy_has_link_generic - Polls PHY for link
* @hw: pointer to the HW structure
diff --git a/drivers/net/intel/e1000/base/e1000_phy.h b/drivers/net/intel/e1000/base/e1000_phy.h
index 4c0b93c18f..d8fcc7ae10 100644
--- a/drivers/net/intel/e1000/base/e1000_phy.h
+++ b/drivers/net/intel/e1000/base/e1000_phy.h
@@ -11,6 +11,7 @@ void e1000_null_phy_generic(struct e1000_hw *hw);
s32 e1000_null_lplu_state(struct e1000_hw *hw, bool active);
s32 e1000_null_write_reg(struct e1000_hw *hw, u32 offset, u16 data);
s32 e1000_null_set_page(struct e1000_hw *hw, u16 data);
+s32 e1000_null_an_status(struct e1000_hw *hw, u8 *status);
s32 e1000_read_i2c_byte_null(struct e1000_hw *hw, u8 byte_offset,
u8 dev_addr, u8 *data);
s32 e1000_write_i2c_byte_null(struct e1000_hw *hw, u8 byte_offset,
@@ -22,6 +23,7 @@ s32 e1000_check_polarity_ife(struct e1000_hw *hw);
s32 e1000_check_reset_block_generic(struct e1000_hw *hw);
s32 e1000_phy_setup_autoneg(struct e1000_hw *hw);
s32 e1000_copper_link_autoneg(struct e1000_hw *hw);
+s32 e1000_1gbase_t_autoneg_status(struct e1000_hw *hw, u8 *an_status);
s32 e1000_copper_link_setup_igp(struct e1000_hw *hw);
s32 e1000_copper_link_setup_m88(struct e1000_hw *hw);
s32 e1000_copper_link_setup_m88_gen2(struct e1000_hw *hw);
--
2.43.0
next prev parent reply other threads:[~2026-05-20 12:54 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-20 12:52 [PATCH 00/10] e1000 base code update Ciara Loftus
2026-05-20 12:52 ` [PATCH 01/10] net/e1000/base: refactor K1 exit timeout configuration Ciara Loftus
2026-05-20 12:52 ` [PATCH 02/10] net/e1000/base: fix typo in e1000 base code Ciara Loftus
2026-05-20 12:52 ` [PATCH 03/10] net/e1000/base: fix possible variable overflow Ciara Loftus
2026-05-20 12:52 ` [PATCH 04/10] net/e1000/base: reclassify MAC type Ciara Loftus
2026-05-20 12:52 ` [PATCH 05/10] net/e1000/base: clear DPG enable bit post MAC reset Ciara Loftus
2026-05-21 16:42 ` Bruce Richardson
2026-05-20 12:52 ` [PATCH 06/10] net/e1000/base: fix coding style issues Ciara Loftus
2026-05-20 12:52 ` [PATCH 07/10] net/e1000/base: fix NVM loop bounds and pointer access Ciara Loftus
2026-05-20 12:52 ` [PATCH 08/10] net/e1000/base: propagate PHY control register write error Ciara Loftus
2026-05-20 12:52 ` Ciara Loftus [this message]
2026-05-20 12:52 ` [PATCH 10/10] net/e1000/base: update version info Ciara Loftus
2026-05-21 16:47 ` [PATCH 00/10] e1000 base code update Bruce Richardson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260520125256.354336-10-ciara.loftus@intel.com \
--to=ciara.loftus@intel.com \
--cc=dev@dpdk.org \
--cc=mateusz.fryze@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox