>-----Original Message-----
>From: Intel-wired-lan <[email protected]> On Behalf Of
>Chia-Lin Kao (AceLan) via Intel-wired-lan
>Sent: Thursday, June 18, 2026 9:33 AM
>To: Nguyen, Anthony L <[email protected]>; Kitszel, Przemyslaw
><[email protected]>
>Cc: Andrew Lunn <[email protected]>; David S. Miller
><[email protected]>; Eric Dumazet <[email protected]>; Jakub Kicinski
><[email protected]>; Paolo Abeni <[email protected]>;
>[email protected]; [email protected];
>[email protected]
>Subject: [Intel-wired-lan] [PATCH 1/2] igc: Wait for MAC passthrough after
>reset
>
>Some systems support MAC passthrough for dock Ethernet controllers by having
>firmware rewrite the receive address registers after the controller reset
>completes.
>
>igc resets the controller before reading RAL0/RAH0, so that reset can restore
>the controller native MAC address temporarily. If the driver reads the
>registers immediately, it can race the firmware rewrite and keep the native
>dock MAC instead of the host passthrough MAC.
>
>For LMVP devices, poll RAL0/RAH0 after reset and before reading the MAC
>address. Stop once the address registers change to another valid Ethernet
>address, allowing firmware a bounded window to complete the passthrough update.
>
>Signed-off-by: Chia-Lin Kao (AceLan) <[email protected]>
>---
> drivers/net/ethernet/intel/igc/igc_main.c | 48 +++++++++++++++++++++++
> 1 file changed, 48 insertions(+)
>
>diff --git a/drivers/net/ethernet/intel/igc/igc_main.c
>b/drivers/net/ethernet/intel/igc/igc_main.c
>index 2c9e2dfd8499..fa9752ed8bc5 100644
>--- a/drivers/net/ethernet/intel/igc/igc_main.c
>+++ b/drivers/net/ethernet/intel/igc/igc_main.c
>@@ -11,6 +11,7 @@
> #include <net/pkt_sched.h>
> #include <linux/bpf_trace.h>
> #include <net/xdp_sock_drv.h>
>+#include <linux/etherdevice.h>
> #include <linux/pci.h>
> #include <linux/mdio.h>
>
>@@ -69,6 +70,52 @@ static const struct pci_device_id igc_pci_tbl[] = {
>
> MODULE_DEVICE_TABLE(pci, igc_pci_tbl);
>
>+static void igc_read_rar0(struct igc_hw *hw, u8 *addr, u32 *ral, u32
>+*rah) {
>+ *ral = rd32(IGC_RAL(0));
>+ *rah = rd32(IGC_RAH(0));
>+
>+ addr[0] = *ral & 0xff;
>+ addr[1] = (*ral >> 8) & 0xff;
>+ addr[2] = (*ral >> 16) & 0xff;
>+ addr[3] = (*ral >> 24) & 0xff;
>+ addr[4] = *rah & 0xff;
>+ addr[5] = (*rah >> 8) & 0xff;
>+}
>+
>+static bool igc_is_lmvp_device(struct pci_dev *pdev) {
>+ switch (pdev->device) {
>+ case IGC_DEV_ID_I225_LMVP:
>+ case IGC_DEV_ID_I226_LMVP:
>+ return true;
>+ default:
>+ return false;
>+ }
>+}
>+
>+static void igc_wait_for_lmvp_mac_passthrough(struct pci_dev *pdev,
>+ struct igc_hw *hw)
>+{
>+ u8 addr[ETH_ALEN] __aligned(2);
>+ u32 orig_ral, orig_rah;
>+ u32 ral, rah;
>+ int i;
Hello AceLan
Please move ral, rah and 'i' right into the loop.
Thank you.
Piotr
>+
>+ if (!igc_is_lmvp_device(pdev))
>+ return;
>+
>+ igc_read_rar0(hw, addr, &orig_ral, &orig_rah);
>+
>+ for (i = 0; i < 100; i++) {
>+ msleep(100);
>+ igc_read_rar0(hw, addr, &ral, &rah);
>+ if ((ral != orig_ral || rah != orig_rah) &&
>+ is_valid_ether_addr(addr))
>+ return;
>+ }
>+}
>+
> enum latency_range {
> lowest_latency = 0,
> low_latency = 1,
>@@ -7259,6 +7306,7 @@ static int igc_probe(struct pci_dev *pdev,
> * known good starting state
> */
> hw->mac.ops.reset_hw(hw);
>+ igc_wait_for_lmvp_mac_passthrough(pdev, hw);
>
> if (igc_get_flash_presence_i225(hw)) {
> if (hw->nvm.ops.validate(hw) < 0) {
>--
>2.53.0
>
>