* [PATCH net-next 01/15] igc: Call netif_queue_set_napi() with rtnl locked
2026-03-30 23:02 [PATCH net-next 00/15][pull request] Intel Wired LAN Driver Updates 2026-03-30 (igc, igb, ice) Tony Nguyen
@ 2026-03-30 23:02 ` Tony Nguyen
2026-03-31 17:37 ` Bjorn Helgaas
2026-03-30 23:02 ` [PATCH net-next 02/15] igc: Let the PCI core deal with the PM resume flow Tony Nguyen
` (13 subsequent siblings)
14 siblings, 1 reply; 22+ messages in thread
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Mika Westerberg, anthony.l.nguyen, andriy.shevchenko,
ilpo.jarvinen, dima.ruinskiy, mbloch, leon, linux-pci, saeedm,
tariqt, lukas, bhelgaas, richardcochran, Vinicius Costa Gomes,
Jacob Keller, Avigail Dahan
From: Mika Westerberg <mika.westerberg@linux.intel.com>
When runtime resuming igc we get:
[ 516.161666] RTNL: assertion failed at ./include/net/netdev_lock.h (72)
Happens because commit 310ae9eb2617 ("net: designate queue -> napi
linking as "ops protected"") added check for this. For this reason drop
the special case for runtime PM from __igc_resume(). This makes it take
rtnl lock unconditionally.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Avigail Dahan <avigailx.dahan@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igc/igc_main.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 72bc5128d8b8..98024b46789f 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -7536,7 +7536,7 @@ static void igc_deliver_wake_packet(struct net_device *netdev)
netif_rx(skb);
}
-static int __igc_resume(struct device *dev, bool rpm)
+static int __igc_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *netdev = pci_get_drvdata(pdev);
@@ -7581,11 +7581,9 @@ static int __igc_resume(struct device *dev, bool rpm)
wr32(IGC_WUS, ~0);
if (netif_running(netdev)) {
- if (!rpm)
- rtnl_lock();
+ rtnl_lock();
err = __igc_open(netdev, true);
- if (!rpm)
- rtnl_unlock();
+ rtnl_unlock();
if (!err)
netif_device_attach(netdev);
}
@@ -7595,12 +7593,12 @@ static int __igc_resume(struct device *dev, bool rpm)
static int igc_resume(struct device *dev)
{
- return __igc_resume(dev, false);
+ return __igc_resume(dev);
}
static int igc_runtime_resume(struct device *dev)
{
- return __igc_resume(dev, true);
+ return __igc_resume(dev);
}
static int igc_suspend(struct device *dev)
--
2.47.1
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH net-next 01/15] igc: Call netif_queue_set_napi() with rtnl locked
2026-03-30 23:02 ` [PATCH net-next 01/15] igc: Call netif_queue_set_napi() with rtnl locked Tony Nguyen
@ 2026-03-31 17:37 ` Bjorn Helgaas
2026-04-02 10:29 ` Paolo Abeni
0 siblings, 1 reply; 22+ messages in thread
From: Bjorn Helgaas @ 2026-03-31 17:37 UTC (permalink / raw)
To: Tony Nguyen
Cc: davem, kuba, pabeni, edumazet, andrew+netdev, netdev,
Mika Westerberg, andriy.shevchenko, ilpo.jarvinen, dima.ruinskiy,
mbloch, leon, linux-pci, saeedm, tariqt, lukas, bhelgaas,
richardcochran, Vinicius Costa Gomes, Jacob Keller, Avigail Dahan
On Mon, Mar 30, 2026 at 04:02:30PM -0700, Tony Nguyen wrote:
> From: Mika Westerberg <mika.westerberg@linux.intel.com>
>
> When runtime resuming igc we get:
>
> [ 516.161666] RTNL: assertion failed at ./include/net/netdev_lock.h (72)
>
> Happens because commit 310ae9eb2617 ("net: designate queue -> napi
> linking as "ops protected"") added check for this. For this reason drop
> the special case for runtime PM from __igc_resume(). This makes it take
> rtnl lock unconditionally.
Taking the rtnl lock unconditionally certainly makes the code nicer,
but the commit log only mentions the "avoid the warning" benefit, not
the actual reason this is safe to do.
> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> Acked-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
> Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
> Tested-by: Avigail Dahan <avigailx.dahan@intel.com>
> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
> ---
> drivers/net/ethernet/intel/igc/igc_main.c | 12 +++++-------
> 1 file changed, 5 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
> index 72bc5128d8b8..98024b46789f 100644
> --- a/drivers/net/ethernet/intel/igc/igc_main.c
> +++ b/drivers/net/ethernet/intel/igc/igc_main.c
> @@ -7536,7 +7536,7 @@ static void igc_deliver_wake_packet(struct net_device *netdev)
> netif_rx(skb);
> }
>
> -static int __igc_resume(struct device *dev, bool rpm)
> +static int __igc_resume(struct device *dev)
> {
> struct pci_dev *pdev = to_pci_dev(dev);
> struct net_device *netdev = pci_get_drvdata(pdev);
> @@ -7581,11 +7581,9 @@ static int __igc_resume(struct device *dev, bool rpm)
> wr32(IGC_WUS, ~0);
>
> if (netif_running(netdev)) {
> - if (!rpm)
> - rtnl_lock();
> + rtnl_lock();
> err = __igc_open(netdev, true);
> - if (!rpm)
> - rtnl_unlock();
> + rtnl_unlock();
> if (!err)
> netif_device_attach(netdev);
> }
> @@ -7595,12 +7593,12 @@ static int __igc_resume(struct device *dev, bool rpm)
>
> static int igc_resume(struct device *dev)
> {
> - return __igc_resume(dev, false);
> + return __igc_resume(dev);
> }
>
> static int igc_runtime_resume(struct device *dev)
> {
> - return __igc_resume(dev, true);
> + return __igc_resume(dev);
> }
>
> static int igc_suspend(struct device *dev)
> --
> 2.47.1
>
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH net-next 01/15] igc: Call netif_queue_set_napi() with rtnl locked
2026-03-31 17:37 ` Bjorn Helgaas
@ 2026-04-02 10:29 ` Paolo Abeni
2026-04-07 6:53 ` Mika Westerberg
0 siblings, 1 reply; 22+ messages in thread
From: Paolo Abeni @ 2026-04-02 10:29 UTC (permalink / raw)
To: Bjorn Helgaas, Tony Nguyen
Cc: davem, kuba, edumazet, andrew+netdev, netdev, Mika Westerberg,
andriy.shevchenko, ilpo.jarvinen, dima.ruinskiy, mbloch, leon,
linux-pci, saeedm, tariqt, lukas, bhelgaas, richardcochran,
Vinicius Costa Gomes, Jacob Keller, Avigail Dahan
On 3/31/26 7:37 PM, Bjorn Helgaas wrote:
> On Mon, Mar 30, 2026 at 04:02:30PM -0700, Tony Nguyen wrote:
>> From: Mika Westerberg <mika.westerberg@linux.intel.com>
>>
>> When runtime resuming igc we get:
>>
>> [ 516.161666] RTNL: assertion failed at ./include/net/netdev_lock.h (72)
>>
>> Happens because commit 310ae9eb2617 ("net: designate queue -> napi
>> linking as "ops protected"") added check for this. For this reason drop
>> the special case for runtime PM from __igc_resume(). This makes it take
>> rtnl lock unconditionally.
>
> Taking the rtnl lock unconditionally certainly makes the code nicer,
> but the commit log only mentions the "avoid the warning" benefit, not
> the actual reason this is safe to do.
Sashiko says it's not safe:
---
Can this regression cause a self-deadlock when a runtime resume is
triggered from paths that already hold the rtnl lock?
If the network interface is logically up but the link is disconnected,
igc_runtime_idle() allows the device to enter runtime suspend. When a
user queries the device using ethtool, the networking core acquires
rtnl_lock() and then calls pm_runtime_get_sync() to ensure the hardware
is awake.
This synchronously executes the driver's runtime resume callback, which
calls __igc_resume(). Because netif_running(netdev) is true, the
modified __igc_resume() unconditionally attempts to acquire rtnl_lock().
Since the executing thread already holds this non-recursive mutex, it
appears the system would self-deadlock, hanging the network stack.
---
/P
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH net-next 01/15] igc: Call netif_queue_set_napi() with rtnl locked
2026-04-02 10:29 ` Paolo Abeni
@ 2026-04-07 6:53 ` Mika Westerberg
0 siblings, 0 replies; 22+ messages in thread
From: Mika Westerberg @ 2026-04-07 6:53 UTC (permalink / raw)
To: Paolo Abeni
Cc: Bjorn Helgaas, Tony Nguyen, davem, kuba, edumazet, andrew+netdev,
netdev, andriy.shevchenko, ilpo.jarvinen, dima.ruinskiy, mbloch,
leon, linux-pci, saeedm, tariqt, lukas, bhelgaas, richardcochran,
Vinicius Costa Gomes, Jacob Keller, Avigail Dahan
Hi,
On Thu, Apr 02, 2026 at 12:29:06PM +0200, Paolo Abeni wrote:
> On 3/31/26 7:37 PM, Bjorn Helgaas wrote:
> > On Mon, Mar 30, 2026 at 04:02:30PM -0700, Tony Nguyen wrote:
> >> From: Mika Westerberg <mika.westerberg@linux.intel.com>
> >>
> >> When runtime resuming igc we get:
> >>
> >> [ 516.161666] RTNL: assertion failed at ./include/net/netdev_lock.h (72)
> >>
> >> Happens because commit 310ae9eb2617 ("net: designate queue -> napi
> >> linking as "ops protected"") added check for this. For this reason drop
> >> the special case for runtime PM from __igc_resume(). This makes it take
> >> rtnl lock unconditionally.
> >
> > Taking the rtnl lock unconditionally certainly makes the code nicer,
> > but the commit log only mentions the "avoid the warning" benefit, not
> > the actual reason this is safe to do.
>
> Sashiko says it's not safe:
>
> ---
> Can this regression cause a self-deadlock when a runtime resume is
> triggered from paths that already hold the rtnl lock?
> If the network interface is logically up but the link is disconnected,
> igc_runtime_idle() allows the device to enter runtime suspend. When a
> user queries the device using ethtool, the networking core acquires
> rtnl_lock() and then calls pm_runtime_get_sync() to ensure the hardware
> is awake.
> This synchronously executes the driver's runtime resume callback, which
> calls __igc_resume(). Because netif_running(netdev) is true, the
> modified __igc_resume() unconditionally attempts to acquire rtnl_lock().
> Since the executing thread already holds this non-recursive mutex, it
> appears the system would self-deadlock, hanging the network stack.
> ---
It's a good analysis. I just tried this flow:
1. Boot the system up, nothing connected to igc NIC.
2. Plug in cable to igc.
3. Configure the interface.
4. Enable runtime PM for igc.
5. Unplug the cable.
6. Verify igc is runtime suspended.
7. Run ethtool <interface>
This leads to deadlock as below.
igc maintainers, please drop this patch. I apologize I did not realize this
flow when I did it.
[ 1231.655924] INFO: task ethtool:3139 blocked for more than 122 seconds.
[ 1231.662515] Tainted: G U 7.0.0-rc6+ #1748
[ 1231.668551] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
[ 1231.676410] task:ethtool state:D stack:0 pid:3139 tgid:3139 ppid:292 task_flags:0x480000 flags:0x00080800
[ 1231.687508] Call Trace:
[ 1231.689997] <TASK>
[ 1231.692132] __schedule+0x58a/0x1820
[ 1231.695747] ? sysvec_apic_timer_interrupt+0x4c/0xa0
[ 1231.700742] ? asm_sysvec_apic_timer_interrupt+0x1b/0x20
[ 1231.706090] schedule+0x64/0xe0
[ 1231.709262] schedule_preempt_disabled+0x15/0x30
[ 1231.713907] __mutex_lock+0x377/0xa60
[ 1231.717606] __mutex_lock_slowpath+0x13/0x20
[ 1231.721905] mutex_lock+0x2c/0x40
[ 1231.725259] rtnl_lock+0x15/0x20
[ 1231.728541] __igc_resume+0x19a/0x2b0 [igc]
[ 1231.732798] igc_runtime_resume+0xe/0x20 [igc]
[ 1231.737288] pci_pm_runtime_resume+0xce/0x100
[ 1231.741678] ? __pfx_pci_pm_runtime_resume+0x10/0x10
[ 1231.746681] __rpm_callback+0xab/0x310
[ 1231.750458] ? ktime_get_mono_fast_ns+0x3a/0x100
[ 1231.755107] ? __pfx_pci_pm_runtime_resume+0x10/0x10
[ 1231.760096] rpm_resume+0x4bb/0x670
[ 1231.763618] __pm_runtime_resume+0x5c/0x80
[ 1231.767749] dev_ethtool+0x19d/0xc90
[ 1231.771352] dev_ioctl+0x23c/0x550
[ 1231.774791] sock_do_ioctl+0x11f/0x1b0
[ 1231.778569] sock_ioctl+0x27f/0x390
[ 1231.782091] ? handle_mm_fault+0x11a5/0x1250
[ 1231.786388] __se_sys_ioctl+0x75/0xd0
[ 1231.790077] __x64_sys_ioctl+0x1d/0x30
[ 1231.793851] x64_sys_call+0x14ed/0x2d30
[ 1231.797719] do_syscall_64+0xfb/0x680
[ 1231.801404] ? arch_exit_to_user_mode_prepare+0xd/0xb0
[ 1231.806559] ? irqentry_exit+0x3b/0x510
[ 1231.810413] entry_SYSCALL_64_after_hwframe+0x76/0x7e
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH net-next 02/15] igc: Let the PCI core deal with the PM resume flow
2026-03-30 23:02 [PATCH net-next 00/15][pull request] Intel Wired LAN Driver Updates 2026-03-30 (igc, igb, ice) Tony Nguyen
2026-03-30 23:02 ` [PATCH net-next 01/15] igc: Call netif_queue_set_napi() with rtnl locked Tony Nguyen
@ 2026-03-30 23:02 ` Tony Nguyen
2026-03-31 17:34 ` Bjorn Helgaas
2026-03-30 23:02 ` [PATCH net-next 03/15] igc: Don't reset the hardware on suspend path Tony Nguyen
` (12 subsequent siblings)
14 siblings, 1 reply; 22+ messages in thread
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Mika Westerberg, anthony.l.nguyen, andriy.shevchenko,
ilpo.jarvinen, dima.ruinskiy, mbloch, leon, linux-pci, saeedm,
tariqt, lukas, bhelgaas, richardcochran, Vinicius Costa Gomes,
Jacob Keller, Avigail Dahan
From: Mika Westerberg <mika.westerberg@linux.intel.com>
Currently igc driver calls pci_set_power_state() and pci_restore_state()
and the like to bring the device back from low power states. However,
PCI core handles all this on behalf of the driver. Furthermore with PTM
enabled the PCI core re-enables it on resume but the driver calls
pci_restore_state() which ends up disabling it again.
For this reason let the PCI core handle the common PM resume flow.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Acked-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Avigail Dahan <avigailx.dahan@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igc/igc_main.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 98024b46789f..0e785af0a3a3 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -7544,9 +7544,6 @@ static int __igc_resume(struct device *dev)
struct igc_hw *hw = &adapter->hw;
u32 err, val;
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
-
if (!pci_device_is_present(pdev))
return -ENODEV;
err = pci_enable_device_mem(pdev);
@@ -7556,9 +7553,6 @@ static int __igc_resume(struct device *dev)
}
pci_set_master(pdev);
- pci_enable_wake(pdev, PCI_D3hot, 0);
- pci_enable_wake(pdev, PCI_D3cold, 0);
-
if (igc_is_device_id_i226(hw))
pci_disable_link_state(pdev, PCIE_LINK_STATE_L1_2);
--
2.47.1
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH net-next 02/15] igc: Let the PCI core deal with the PM resume flow
2026-03-30 23:02 ` [PATCH net-next 02/15] igc: Let the PCI core deal with the PM resume flow Tony Nguyen
@ 2026-03-31 17:34 ` Bjorn Helgaas
0 siblings, 0 replies; 22+ messages in thread
From: Bjorn Helgaas @ 2026-03-31 17:34 UTC (permalink / raw)
To: Tony Nguyen
Cc: davem, kuba, pabeni, edumazet, andrew+netdev, netdev,
Mika Westerberg, andriy.shevchenko, ilpo.jarvinen, dima.ruinskiy,
mbloch, leon, linux-pci, saeedm, tariqt, lukas, bhelgaas,
richardcochran, Vinicius Costa Gomes, Jacob Keller, Avigail Dahan
On Mon, Mar 30, 2026 at 04:02:31PM -0700, Tony Nguyen wrote:
> From: Mika Westerberg <mika.westerberg@linux.intel.com>
>
> Currently igc driver calls pci_set_power_state() and pci_restore_state()
> and the like to bring the device back from low power states. However,
> PCI core handles all this on behalf of the driver. Furthermore with PTM
> enabled the PCI core re-enables it on resume but the driver calls
> pci_restore_state() which ends up disabling it again.
>
> For this reason let the PCI core handle the common PM resume flow.
>
> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
> Acked-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
> Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
> Tested-by: Avigail Dahan <avigailx.dahan@intel.com>
> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
I love it, thanks a lot for doing this!
> ---
> drivers/net/ethernet/intel/igc/igc_main.c | 6 ------
> 1 file changed, 6 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
> index 98024b46789f..0e785af0a3a3 100644
> --- a/drivers/net/ethernet/intel/igc/igc_main.c
> +++ b/drivers/net/ethernet/intel/igc/igc_main.c
> @@ -7544,9 +7544,6 @@ static int __igc_resume(struct device *dev)
> struct igc_hw *hw = &adapter->hw;
> u32 err, val;
>
> - pci_set_power_state(pdev, PCI_D0);
> - pci_restore_state(pdev);
> -
> if (!pci_device_is_present(pdev))
> return -ENODEV;
> err = pci_enable_device_mem(pdev);
__igc_shutdown() calls pci_disable_device() in the suspend paths,
which disables bus mastering. There are only a relative handful of
drivers that do this, mostly for NICs, so I'm not sure if it's really
necessary or if it's been cargo-culted.
Here in the resume path we call pci_enable_device_mem(),
pci_set_master(), and conditionally call pci_disable_link_state(). I
suspect all those are unnecessary because pci_pm_resume() should have
called pci_restore_state() before we get here.
> @@ -7556,9 +7553,6 @@ static int __igc_resume(struct device *dev)
> }
> pci_set_master(pdev);
>
> - pci_enable_wake(pdev, PCI_D3hot, 0);
> - pci_enable_wake(pdev, PCI_D3cold, 0);
> -
> if (igc_is_device_id_i226(hw))
> pci_disable_link_state(pdev, PCIE_LINK_STATE_L1_2);
>
> --
> 2.47.1
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH net-next 03/15] igc: Don't reset the hardware on suspend path
2026-03-30 23:02 [PATCH net-next 00/15][pull request] Intel Wired LAN Driver Updates 2026-03-30 (igc, igb, ice) Tony Nguyen
2026-03-30 23:02 ` [PATCH net-next 01/15] igc: Call netif_queue_set_napi() with rtnl locked Tony Nguyen
2026-03-30 23:02 ` [PATCH net-next 02/15] igc: Let the PCI core deal with the PM resume flow Tony Nguyen
@ 2026-03-30 23:02 ` Tony Nguyen
2026-03-30 23:02 ` [PATCH net-next 04/15] igc: prepare for RSS key get/set support Tony Nguyen
` (11 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Mika Westerberg, anthony.l.nguyen, andriy.shevchenko,
ilpo.jarvinen, dima.ruinskiy, mbloch, leon, linux-pci, saeedm,
tariqt, lukas, bhelgaas, richardcochran, Vinicius Costa Gomes,
Jacob Keller, Avigail Dahan
From: Mika Westerberg <mika.westerberg@linux.intel.com>
Commit c01163dbd1b8 ("PCI/PM: Always disable PTM for all devices during
suspend") made the PCI core to suspend (disable) PTM before driver
suspend hooks are called. In case of igc what happens is that on suspend
path PCI core calls pci_suspend_ptm() then igc suspend hook that calls
igc_down() that ends up calling igc_ptp_reset() (which according to the
comment is actually needed for re-enabling the device). Anyways that
function also poll IGC_PTM_STAT that will end up timing out because PTM
is already disabled:
[ 160.716119] igc 0000:03:00.0 enp3s0: Timeout reading IGC_PTM_STAT register
There should be no reason resetting the hardware on suspend path so fix
this by avoiding the reset.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Avigail Dahan <avigailx.dahan@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igc/igc.h | 2 +-
drivers/net/ethernet/intel/igc/igc_ethtool.c | 6 +++---
drivers/net/ethernet/intel/igc/igc_main.c | 13 +++++++------
3 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h
index 17236813965d..caa5b89b2b24 100644
--- a/drivers/net/ethernet/intel/igc/igc.h
+++ b/drivers/net/ethernet/intel/igc/igc.h
@@ -349,7 +349,7 @@ struct igc_adapter {
};
void igc_up(struct igc_adapter *adapter);
-void igc_down(struct igc_adapter *adapter);
+void igc_down(struct igc_adapter *adapter, bool reset);
int igc_open(struct net_device *netdev);
int igc_close(struct net_device *netdev);
int igc_setup_tx_resources(struct igc_ring *ring);
diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c
index 0122009bedd0..4d1bcc19255f 100644
--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c
+++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c
@@ -638,7 +638,7 @@ igc_ethtool_set_ringparam(struct net_device *netdev,
goto clear_reset;
}
- igc_down(adapter);
+ igc_down(adapter, true);
/* We can't just free everything and then setup again,
* because the ISRs in MSI-X mode get passed pointers
@@ -737,7 +737,7 @@ static int igc_ethtool_set_pauseparam(struct net_device *netdev,
if (adapter->fc_autoneg == AUTONEG_ENABLE) {
hw->fc.requested_mode = igc_fc_default;
if (netif_running(adapter->netdev)) {
- igc_down(adapter);
+ igc_down(adapter, true);
igc_up(adapter);
} else {
igc_reset(adapter);
@@ -2077,7 +2077,7 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev,
/* reset the link */
if (netif_running(adapter->netdev)) {
- igc_down(adapter);
+ igc_down(adapter, true);
igc_up(adapter);
} else {
igc_reset(adapter);
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 0e785af0a3a3..80a90ce0ad0e 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -5312,8 +5312,9 @@ void igc_update_stats(struct igc_adapter *adapter)
/**
* igc_down - Close the interface
* @adapter: board private structure
+ * @reset: issue reset
*/
-void igc_down(struct igc_adapter *adapter)
+void igc_down(struct igc_adapter *adapter, bool reset)
{
struct net_device *netdev = adapter->netdev;
struct igc_hw *hw = &adapter->hw;
@@ -5369,7 +5370,7 @@ void igc_down(struct igc_adapter *adapter)
adapter->link_speed = 0;
adapter->link_duplex = 0;
- if (!pci_channel_offline(adapter->pdev))
+ if (reset && !pci_channel_offline(adapter->pdev))
igc_reset(adapter);
/* clear VLAN promisc flag so VFTA will be updated if necessary */
@@ -5387,7 +5388,7 @@ void igc_reinit_locked(struct igc_adapter *adapter)
{
while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
usleep_range(1000, 2000);
- igc_down(adapter);
+ igc_down(adapter, true);
igc_up(adapter);
clear_bit(__IGC_RESETTING, &adapter->state);
}
@@ -5441,7 +5442,7 @@ static int igc_change_mtu(struct net_device *netdev, int new_mtu)
adapter->max_frame_size = max_frame;
if (netif_running(netdev))
- igc_down(adapter);
+ igc_down(adapter, true);
netdev_dbg(netdev, "changing MTU from %d to %d\n", netdev->mtu, new_mtu);
WRITE_ONCE(netdev->mtu, new_mtu);
@@ -6305,7 +6306,7 @@ static int __igc_close(struct net_device *netdev, bool suspending)
if (!suspending)
pm_runtime_get_sync(&pdev->dev);
- igc_down(adapter);
+ igc_down(adapter, !suspending);
igc_release_hw_control(adapter);
@@ -7646,7 +7647,7 @@ static pci_ers_result_t igc_io_error_detected(struct pci_dev *pdev,
}
if (netif_running(netdev))
- igc_down(adapter);
+ igc_down(adapter, true);
pci_disable_device(pdev);
rtnl_unlock();
--
2.47.1
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH net-next 04/15] igc: prepare for RSS key get/set support
2026-03-30 23:02 [PATCH net-next 00/15][pull request] Intel Wired LAN Driver Updates 2026-03-30 (igc, igb, ice) Tony Nguyen
` (2 preceding siblings ...)
2026-03-30 23:02 ` [PATCH net-next 03/15] igc: Don't reset the hardware on suspend path Tony Nguyen
@ 2026-03-30 23:02 ` Tony Nguyen
2026-03-30 23:02 ` [PATCH net-next 05/15] igc: expose RSS key via ethtool get_rxfh Tony Nguyen
` (10 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Kohei Enju, anthony.l.nguyen, dima.ruinskiy, kohei.enju, horms,
Aleksandr Loktionov, Avigail Dahan
From: Kohei Enju <kohei@enjuk.jp>
Store the RSS key inside struct igc_adapter and introduce the
igc_write_rss_key() helper function. This allows the driver to program
the RSSRK registers using a persistent RSS key, instead of using a
stack-local buffer in igc_setup_mrqc().
This is a preparation patch for adding RSS key get/set support in
subsequent changes, and no functional change is intended in this patch.
Signed-off-by: Kohei Enju <kohei@enjuk.jp>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Avigail Dahan <avigailx.dahan@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igc/igc.h | 3 +++
drivers/net/ethernet/intel/igc/igc_ethtool.c | 20 ++++++++++++++++++++
drivers/net/ethernet/intel/igc/igc_main.c | 8 ++++----
3 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h
index caa5b89b2b24..e66799507f81 100644
--- a/drivers/net/ethernet/intel/igc/igc.h
+++ b/drivers/net/ethernet/intel/igc/igc.h
@@ -30,6 +30,7 @@ void igc_ethtool_set_ops(struct net_device *);
#define MAX_ETYPE_FILTER 8
#define IGC_RETA_SIZE 128
+#define IGC_RSS_KEY_SIZE 40
/* SDP support */
#define IGC_N_EXTTS 2
@@ -302,6 +303,7 @@ struct igc_adapter {
unsigned int nfc_rule_count;
u8 rss_indir_tbl[IGC_RETA_SIZE];
+ u8 rss_key[IGC_RSS_KEY_SIZE];
unsigned long link_check_timeout;
struct igc_info ei;
@@ -360,6 +362,7 @@ unsigned int igc_get_max_rss_queues(struct igc_adapter *adapter);
void igc_set_flag_queue_pairs(struct igc_adapter *adapter,
const u32 max_rss_queues);
int igc_reinit_queues(struct igc_adapter *adapter);
+void igc_write_rss_key(struct igc_adapter *adapter);
void igc_write_rss_indir_tbl(struct igc_adapter *adapter);
bool igc_has_link(struct igc_adapter *adapter);
void igc_reset(struct igc_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c
index 4d1bcc19255f..c2300232c8b1 100644
--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c
+++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c
@@ -1460,6 +1460,26 @@ static int igc_ethtool_set_rxnfc(struct net_device *dev,
}
}
+/**
+ * igc_write_rss_key - Program the RSS key into device registers
+ * @adapter: board private structure
+ *
+ * Write the RSS key stored in adapter->rss_key to the IGC_RSSRK registers.
+ * Each 32-bit chunk of the key is read using get_unaligned_le32() and written
+ * to the appropriate register.
+ */
+void igc_write_rss_key(struct igc_adapter *adapter)
+{
+ struct igc_hw *hw = &adapter->hw;
+ u32 val;
+ int i;
+
+ for (i = 0; i < IGC_RSS_KEY_SIZE / 4; i++) {
+ val = get_unaligned_le32(&adapter->rss_key[i * 4]);
+ wr32(IGC_RSSRK(i), val);
+ }
+}
+
void igc_write_rss_indir_tbl(struct igc_adapter *adapter)
{
struct igc_hw *hw = &adapter->hw;
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 80a90ce0ad0e..ebd831a4ff53 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -785,11 +785,8 @@ static void igc_setup_mrqc(struct igc_adapter *adapter)
struct igc_hw *hw = &adapter->hw;
u32 j, num_rx_queues;
u32 mrqc, rxcsum;
- u32 rss_key[10];
- netdev_rss_key_fill(rss_key, sizeof(rss_key));
- for (j = 0; j < 10; j++)
- wr32(IGC_RSSRK(j), rss_key[j]);
+ igc_write_rss_key(adapter);
num_rx_queues = adapter->rss_queues;
@@ -5048,6 +5045,9 @@ static int igc_sw_init(struct igc_adapter *adapter)
pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
+ /* init RSS key */
+ netdev_rss_key_fill(adapter->rss_key, sizeof(adapter->rss_key));
+
/* set default ring sizes */
adapter->tx_ring_count = IGC_DEFAULT_TXD;
adapter->rx_ring_count = IGC_DEFAULT_RXD;
--
2.47.1
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH net-next 05/15] igc: expose RSS key via ethtool get_rxfh
2026-03-30 23:02 [PATCH net-next 00/15][pull request] Intel Wired LAN Driver Updates 2026-03-30 (igc, igb, ice) Tony Nguyen
` (3 preceding siblings ...)
2026-03-30 23:02 ` [PATCH net-next 04/15] igc: prepare for RSS key get/set support Tony Nguyen
@ 2026-03-30 23:02 ` Tony Nguyen
2026-03-30 23:02 ` [PATCH net-next 06/15] igc: allow configuring RSS key via ethtool set_rxfh Tony Nguyen
` (9 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Kohei Enju, anthony.l.nguyen, dima.ruinskiy, kohei.enju, horms,
Avigail Dahan, Aleksandr Loktionov
From: Kohei Enju <kohei@enjuk.jp>
Implement igc_ethtool_get_rxfh_key_size() and extend
igc_ethtool_get_rxfh() to return the RSS key to userspace.
This can be tested using `ethtool -x <dev>`.
Signed-off-by: Kohei Enju <kohei@enjuk.jp>
Tested-by: Avigail Dahan <avigailx.dahan@intel.com>
Reviewed-by: Vitaly Lifshits <vitaly.lifshits@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igc/igc_ethtool.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c
index c2300232c8b1..abe8eb695c2a 100644
--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c
+++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c
@@ -1502,6 +1502,11 @@ void igc_write_rss_indir_tbl(struct igc_adapter *adapter)
}
}
+static u32 igc_ethtool_get_rxfh_key_size(struct net_device *netdev)
+{
+ return IGC_RSS_KEY_SIZE;
+}
+
static u32 igc_ethtool_get_rxfh_indir_size(struct net_device *netdev)
{
return IGC_RETA_SIZE;
@@ -1514,10 +1519,13 @@ static int igc_ethtool_get_rxfh(struct net_device *netdev,
int i;
rxfh->hfunc = ETH_RSS_HASH_TOP;
- if (!rxfh->indir)
- return 0;
- for (i = 0; i < IGC_RETA_SIZE; i++)
- rxfh->indir[i] = adapter->rss_indir_tbl[i];
+
+ if (rxfh->indir)
+ for (i = 0; i < IGC_RETA_SIZE; i++)
+ rxfh->indir[i] = adapter->rss_indir_tbl[i];
+
+ if (rxfh->key)
+ memcpy(rxfh->key, adapter->rss_key, sizeof(adapter->rss_key));
return 0;
}
@@ -2195,6 +2203,7 @@ static const struct ethtool_ops igc_ethtool_ops = {
.get_rxnfc = igc_ethtool_get_rxnfc,
.set_rxnfc = igc_ethtool_set_rxnfc,
.get_rx_ring_count = igc_ethtool_get_rx_ring_count,
+ .get_rxfh_key_size = igc_ethtool_get_rxfh_key_size,
.get_rxfh_indir_size = igc_ethtool_get_rxfh_indir_size,
.get_rxfh = igc_ethtool_get_rxfh,
.set_rxfh = igc_ethtool_set_rxfh,
--
2.47.1
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH net-next 06/15] igc: allow configuring RSS key via ethtool set_rxfh
2026-03-30 23:02 [PATCH net-next 00/15][pull request] Intel Wired LAN Driver Updates 2026-03-30 (igc, igb, ice) Tony Nguyen
` (4 preceding siblings ...)
2026-03-30 23:02 ` [PATCH net-next 05/15] igc: expose RSS key via ethtool get_rxfh Tony Nguyen
@ 2026-03-30 23:02 ` Tony Nguyen
2026-03-30 23:02 ` [PATCH net-next 07/15] igb: prepare for RSS key get/set support Tony Nguyen
` (8 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Kohei Enju, anthony.l.nguyen, dima.ruinskiy, kohei.enju, horms,
Avigail Dahan
From: Kohei Enju <kohei@enjuk.jp>
Change igc_ethtool_set_rxfh() to accept and save a userspace-provided
RSS key. When a key is provided, store it in the adapter and write the
RSSRK registers accordingly.
This can be tested using `ethtool -X <dev> hkey <key>`.
Signed-off-by: Kohei Enju <kohei@enjuk.jp>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Avigail Dahan <avigailx.dahan@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igc/igc_ethtool.c | 30 +++++++++++---------
1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c
index abe8eb695c2a..3a63c6db4241 100644
--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c
+++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c
@@ -1539,24 +1539,28 @@ static int igc_ethtool_set_rxfh(struct net_device *netdev,
int i;
/* We do not allow change in unsupported parameters */
- if (rxfh->key ||
- (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
- rxfh->hfunc != ETH_RSS_HASH_TOP))
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- if (!rxfh->indir)
- return 0;
- num_queues = adapter->rss_queues;
+ if (rxfh->indir) {
+ num_queues = adapter->rss_queues;
- /* Verify user input. */
- for (i = 0; i < IGC_RETA_SIZE; i++)
- if (rxfh->indir[i] >= num_queues)
- return -EINVAL;
+ /* Verify user input. */
+ for (i = 0; i < IGC_RETA_SIZE; i++)
+ if (rxfh->indir[i] >= num_queues)
+ return -EINVAL;
- for (i = 0; i < IGC_RETA_SIZE; i++)
- adapter->rss_indir_tbl[i] = rxfh->indir[i];
+ for (i = 0; i < IGC_RETA_SIZE; i++)
+ adapter->rss_indir_tbl[i] = rxfh->indir[i];
- igc_write_rss_indir_tbl(adapter);
+ igc_write_rss_indir_tbl(adapter);
+ }
+
+ if (rxfh->key) {
+ memcpy(adapter->rss_key, rxfh->key, sizeof(adapter->rss_key));
+ igc_write_rss_key(adapter);
+ }
return 0;
}
--
2.47.1
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH net-next 07/15] igb: prepare for RSS key get/set support
2026-03-30 23:02 [PATCH net-next 00/15][pull request] Intel Wired LAN Driver Updates 2026-03-30 (igc, igb, ice) Tony Nguyen
` (5 preceding siblings ...)
2026-03-30 23:02 ` [PATCH net-next 06/15] igc: allow configuring RSS key via ethtool set_rxfh Tony Nguyen
@ 2026-03-30 23:02 ` Tony Nguyen
2026-03-30 23:02 ` [PATCH net-next 08/15] igb: expose RSS key via ethtool get_rxfh Tony Nguyen
` (7 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Takashi Kozu, anthony.l.nguyen, horms, enjuk, Piotr Kwapulinski,
Aleksandr Loktionov, Rinitha S
From: Takashi Kozu <takkozu@amazon.com>
Store the RSS key inside struct igb_adapter and introduce the
igb_write_rss_key() helper function. This allows the driver to program
the E1000 registers using a persistent RSS key, instead of using a
stack-local buffer in igb_setup_mrqc().
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Takashi Kozu <takkozu@amazon.com>
Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igb/igb.h | 3 +++
drivers/net/ethernet/intel/igb/igb_ethtool.c | 21 ++++++++++++++++++++
drivers/net/ethernet/intel/igb/igb_main.c | 8 ++++----
3 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 0fff1df81b7b..8c9b02058cec 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -495,6 +495,7 @@ struct hwmon_buff {
#define IGB_N_PEROUT 2
#define IGB_N_SDP 4
#define IGB_RETA_SIZE 128
+#define IGB_RSS_KEY_SIZE 40
enum igb_filter_match_flags {
IGB_FILTER_FLAG_ETHER_TYPE = 0x1,
@@ -655,6 +656,7 @@ struct igb_adapter {
struct i2c_client *i2c_client;
u32 rss_indir_tbl_init;
u8 rss_indir_tbl[IGB_RETA_SIZE];
+ u8 rss_key[IGB_RSS_KEY_SIZE];
unsigned long link_check_timeout;
int copper_tries;
@@ -735,6 +737,7 @@ void igb_down(struct igb_adapter *);
void igb_reinit_locked(struct igb_adapter *);
void igb_reset(struct igb_adapter *);
int igb_reinit_queues(struct igb_adapter *);
+void igb_write_rss_key(struct igb_adapter *adapter);
void igb_write_rss_indir_tbl(struct igb_adapter *);
int igb_set_spd_dplx(struct igb_adapter *, u32, u8);
int igb_setup_tx_resources(struct igb_ring *);
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index f7938c1da835..9a105e59f432 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -3019,6 +3019,27 @@ static int igb_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
return ret;
}
+/**
+ * igb_write_rss_key - Program the RSS key into device registers
+ * @adapter: board private structure
+ *
+ * Write the RSS key stored in adapter->rss_key to the E1000 hardware registers.
+ * Each 32-bit chunk of the key is read using get_unaligned_le32() and written
+ * to the appropriate register.
+ */
+void igb_write_rss_key(struct igb_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+
+ ASSERT_RTNL();
+
+ for (int i = 0; i < IGB_RSS_KEY_SIZE / 4; i++) {
+ u32 val = get_unaligned_le32(&adapter->rss_key[i * 4]);
+
+ wr32(E1000_RSSRK(i), val);
+ }
+}
+
static int igb_get_eee(struct net_device *netdev, struct ethtool_keee *edata)
{
struct igb_adapter *adapter = netdev_priv(netdev);
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index ee99fd8fd513..f40fe12419f1 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -4049,6 +4049,9 @@ static int igb_sw_init(struct igb_adapter *adapter)
pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
+ /* init RSS key */
+ netdev_rss_key_fill(adapter->rss_key, sizeof(adapter->rss_key));
+
/* set default ring sizes */
adapter->tx_ring_count = IGB_DEFAULT_TXD;
adapter->rx_ring_count = IGB_DEFAULT_RXD;
@@ -4523,11 +4526,8 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
u32 mrqc, rxcsum;
u32 j, num_rx_queues;
- u32 rss_key[10];
- netdev_rss_key_fill(rss_key, sizeof(rss_key));
- for (j = 0; j < 10; j++)
- wr32(E1000_RSSRK(j), rss_key[j]);
+ igb_write_rss_key(adapter);
num_rx_queues = adapter->rss_queues;
--
2.47.1
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH net-next 08/15] igb: expose RSS key via ethtool get_rxfh
2026-03-30 23:02 [PATCH net-next 00/15][pull request] Intel Wired LAN Driver Updates 2026-03-30 (igc, igb, ice) Tony Nguyen
` (6 preceding siblings ...)
2026-03-30 23:02 ` [PATCH net-next 07/15] igb: prepare for RSS key get/set support Tony Nguyen
@ 2026-03-30 23:02 ` Tony Nguyen
2026-03-30 23:02 ` [PATCH net-next 09/15] igb: allow configuring RSS key via ethtool set_rxfh Tony Nguyen
` (6 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Takashi Kozu, anthony.l.nguyen, horms, enjuk, Aleksandr Loktionov,
Rinitha S
From: Takashi Kozu <takkozu@amazon.com>
Implement igb_get_rxfh_key_size() and extend
igb_get_rxfh() to return the RSS key to userspace.
This can be tested using `ethtool -x <dev>`.
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Takashi Kozu <takkozu@amazon.com>
Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igb/igb_ethtool.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index 9a105e59f432..47fc620026a9 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -3297,10 +3297,12 @@ static int igb_get_rxfh(struct net_device *netdev,
int i;
rxfh->hfunc = ETH_RSS_HASH_TOP;
- if (!rxfh->indir)
- return 0;
- for (i = 0; i < IGB_RETA_SIZE; i++)
- rxfh->indir[i] = adapter->rss_indir_tbl[i];
+ if (rxfh->indir)
+ for (i = 0; i < IGB_RETA_SIZE; i++)
+ rxfh->indir[i] = adapter->rss_indir_tbl[i];
+
+ if (rxfh->key)
+ memcpy(rxfh->key, adapter->rss_key, sizeof(adapter->rss_key));
return 0;
}
@@ -3340,6 +3342,11 @@ void igb_write_rss_indir_tbl(struct igb_adapter *adapter)
}
}
+static u32 igb_get_rxfh_key_size(struct net_device *netdev)
+{
+ return IGB_RSS_KEY_SIZE;
+}
+
static int igb_set_rxfh(struct net_device *netdev,
struct ethtool_rxfh_param *rxfh,
struct netlink_ext_ack *extack)
@@ -3504,6 +3511,7 @@ static const struct ethtool_ops igb_ethtool_ops = {
.get_module_eeprom = igb_get_module_eeprom,
.get_rxfh_indir_size = igb_get_rxfh_indir_size,
.get_rxfh = igb_get_rxfh,
+ .get_rxfh_key_size = igb_get_rxfh_key_size,
.set_rxfh = igb_set_rxfh,
.get_rxfh_fields = igb_get_rxfh_fields,
.set_rxfh_fields = igb_set_rxfh_fields,
--
2.47.1
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH net-next 09/15] igb: allow configuring RSS key via ethtool set_rxfh
2026-03-30 23:02 [PATCH net-next 00/15][pull request] Intel Wired LAN Driver Updates 2026-03-30 (igc, igb, ice) Tony Nguyen
` (7 preceding siblings ...)
2026-03-30 23:02 ` [PATCH net-next 08/15] igb: expose RSS key via ethtool get_rxfh Tony Nguyen
@ 2026-03-30 23:02 ` Tony Nguyen
2026-03-30 23:02 ` [PATCH net-next 10/15] igb: set skb hash type from RSS_TYPE Tony Nguyen
` (5 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Takashi Kozu, anthony.l.nguyen, horms, enjuk, Kohei Enju,
Rinitha S
From: Takashi Kozu <takkozu@amazon.com>
Change igb_set_rxfh() to accept and save a userspace-provided
RSS key. When a key is provided, store it in the adapter and write the
E1000 registers accordingly.
This can be tested using `ethtool -X <dev> hkey <key>`.
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Takashi Kozu <takkozu@amazon.com>
Tested-by: Kohei Enju <kohei@enjuk.jp>
Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igb/igb_ethtool.c | 48 +++++++++++---------
1 file changed, 26 insertions(+), 22 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index 47fc620026a9..65014a54a6d1 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -3357,35 +3357,39 @@ static int igb_set_rxfh(struct net_device *netdev,
u32 num_queues;
/* We do not allow change in unsupported parameters */
- if (rxfh->key ||
- (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
- rxfh->hfunc != ETH_RSS_HASH_TOP))
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- if (!rxfh->indir)
- return 0;
- num_queues = adapter->rss_queues;
+ if (rxfh->indir) {
+ num_queues = adapter->rss_queues;
- switch (hw->mac.type) {
- case e1000_82576:
- /* 82576 supports 2 RSS queues for SR-IOV */
- if (adapter->vfs_allocated_count)
- num_queues = 2;
- break;
- default:
- break;
- }
+ switch (hw->mac.type) {
+ case e1000_82576:
+ /* 82576 supports 2 RSS queues for SR-IOV */
+ if (adapter->vfs_allocated_count)
+ num_queues = 2;
+ break;
+ default:
+ break;
+ }
- /* Verify user input. */
- for (i = 0; i < IGB_RETA_SIZE; i++)
- if (rxfh->indir[i] >= num_queues)
- return -EINVAL;
+ /* Verify user input. */
+ for (i = 0; i < IGB_RETA_SIZE; i++)
+ if (rxfh->indir[i] >= num_queues)
+ return -EINVAL;
- for (i = 0; i < IGB_RETA_SIZE; i++)
- adapter->rss_indir_tbl[i] = rxfh->indir[i];
+ for (i = 0; i < IGB_RETA_SIZE; i++)
+ adapter->rss_indir_tbl[i] = rxfh->indir[i];
+
+ igb_write_rss_indir_tbl(adapter);
+ }
- igb_write_rss_indir_tbl(adapter);
+ if (rxfh->key) {
+ memcpy(adapter->rss_key, rxfh->key, sizeof(adapter->rss_key));
+ igb_write_rss_key(adapter);
+ }
return 0;
}
--
2.47.1
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH net-next 10/15] igb: set skb hash type from RSS_TYPE
2026-03-30 23:02 [PATCH net-next 00/15][pull request] Intel Wired LAN Driver Updates 2026-03-30 (igc, igb, ice) Tony Nguyen
` (8 preceding siblings ...)
2026-03-30 23:02 ` [PATCH net-next 09/15] igb: allow configuring RSS key via ethtool set_rxfh Tony Nguyen
@ 2026-03-30 23:02 ` Tony Nguyen
2026-03-30 23:02 ` [PATCH net-next 11/15] igb: fix typos in comments Tony Nguyen
` (4 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Kohei Enju, anthony.l.nguyen, kohei.enju, Aleksandr Loktionov,
Paul Menzel
From: Kohei Enju <kohei@enjuk.jp>
igb always marks the RX hash as L3 regardless of RSS_TYPE in the
advanced descriptor, which may indicate L4 (TCP/UDP) hash. This can
trigger unnecessary SW hash recalculation and breaks toeplitz selftests.
Use RSS_TYPE from pkt_info to set the correct PKT_HASH_TYPE_*
Tested by toeplitz.py with the igb RSS key get/set patches applied as
they are required for toeplitz.py (see Link below).
# ethtool -N $DEV rx-flow-hash udp4 sdfn
# ethtool -N $DEV rx-flow-hash udp6 sdfn
# python toeplitz.py | grep -E "^# Totals"
Without patch:
# Totals: pass:0 fail:12 xfail:0 xpass:0 skip:0 error:0
With patch:
# Totals: pass:12 fail:0 xfail:0 xpass:0 skip:0 error:0
Link: https://lore.kernel.org/intel-wired-lan/20260119084511.95287-5-takkozu@amazon.com/
Signed-off-by: Kohei Enju <kohei@enjuk.jp>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igb/e1000_82575.h | 21 ++++++++++++++++++++
drivers/net/ethernet/intel/igb/igb_main.c | 17 ++++++++++++----
2 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h
index 63ec253ac788..9e696d55e512 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.h
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.h
@@ -87,6 +87,27 @@ union e1000_adv_rx_desc {
} wb; /* writeback */
};
+#define E1000_RSS_TYPE_NO_HASH 0
+#define E1000_RSS_TYPE_HASH_TCP_IPV4 1
+#define E1000_RSS_TYPE_HASH_IPV4 2
+#define E1000_RSS_TYPE_HASH_TCP_IPV6 3
+#define E1000_RSS_TYPE_HASH_IPV6_EX 4
+#define E1000_RSS_TYPE_HASH_IPV6 5
+#define E1000_RSS_TYPE_HASH_TCP_IPV6_EX 6
+#define E1000_RSS_TYPE_HASH_UDP_IPV4 7
+#define E1000_RSS_TYPE_HASH_UDP_IPV6 8
+#define E1000_RSS_TYPE_HASH_UDP_IPV6_EX 9
+
+#define E1000_RSS_TYPE_MASK GENMASK(3, 0)
+
+#define E1000_RSS_L4_TYPES_MASK \
+ (BIT(E1000_RSS_TYPE_HASH_TCP_IPV4) | \
+ BIT(E1000_RSS_TYPE_HASH_TCP_IPV6) | \
+ BIT(E1000_RSS_TYPE_HASH_TCP_IPV6_EX) | \
+ BIT(E1000_RSS_TYPE_HASH_UDP_IPV4) | \
+ BIT(E1000_RSS_TYPE_HASH_UDP_IPV6) | \
+ BIT(E1000_RSS_TYPE_HASH_UDP_IPV6_EX))
+
#define E1000_RXDADV_HDRBUFLEN_MASK 0x7FE0
#define E1000_RXDADV_HDRBUFLEN_SHIFT 5
#define E1000_RXDADV_STAT_TS 0x10000 /* Pkt was time stamped */
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index f40fe12419f1..747277d68411 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -8821,10 +8821,19 @@ static inline void igb_rx_hash(struct igb_ring *ring,
union e1000_adv_rx_desc *rx_desc,
struct sk_buff *skb)
{
- if (ring->netdev->features & NETIF_F_RXHASH)
- skb_set_hash(skb,
- le32_to_cpu(rx_desc->wb.lower.hi_dword.rss),
- PKT_HASH_TYPE_L3);
+ u16 rss_type;
+
+ if (!(ring->netdev->features & NETIF_F_RXHASH))
+ return;
+
+ rss_type = le16_to_cpu(rx_desc->wb.lower.lo_dword.pkt_info) &
+ E1000_RSS_TYPE_MASK;
+ if (!rss_type)
+ return;
+
+ skb_set_hash(skb, le32_to_cpu(rx_desc->wb.lower.hi_dword.rss),
+ (E1000_RSS_L4_TYPES_MASK & BIT(rss_type)) ?
+ PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
}
/**
--
2.47.1
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH net-next 11/15] igb: fix typos in comments
2026-03-30 23:02 [PATCH net-next 00/15][pull request] Intel Wired LAN Driver Updates 2026-03-30 (igc, igb, ice) Tony Nguyen
` (9 preceding siblings ...)
2026-03-30 23:02 ` [PATCH net-next 10/15] igb: set skb hash type from RSS_TYPE Tony Nguyen
@ 2026-03-30 23:02 ` Tony Nguyen
2026-03-30 23:02 ` [PATCH net-next 12/15] igc: " Tony Nguyen
` (3 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Maximilian Pezzullo, anthony.l.nguyen, Aleksandr Loktionov,
Joe Damato
From: Maximilian Pezzullo <maximilianpezzullo@gmail.com>
Fix spelling errors in code comments:
- e1000_nvm.c: 'likley' -> 'likely'
- e1000_mac.c: 'auto-negotitation' -> 'auto-negotiation'
- e1000_mbx.h: 'exra' -> 'extra'
- e1000_defines.h: 'Aserted' -> 'Asserted'
Signed-off-by: Maximilian Pezzullo <maximilianpezzullo@gmail.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Joe Damato <joe@dama.to>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igb/e1000_defines.h | 2 +-
drivers/net/ethernet/intel/igb/e1000_mac.c | 2 +-
drivers/net/ethernet/intel/igb/e1000_mbx.h | 2 +-
drivers/net/ethernet/intel/igb/e1000_nvm.c | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h
index fa028928482f..7e6f9aa2d57b 100644
--- a/drivers/net/ethernet/intel/igb/e1000_defines.h
+++ b/drivers/net/ethernet/intel/igb/e1000_defines.h
@@ -442,7 +442,7 @@
/* Interrupt Cause Set */
#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */
#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
-#define E1000_ICS_DRSTA E1000_ICR_DRSTA /* Device Reset Aserted */
+#define E1000_ICS_DRSTA E1000_ICR_DRSTA /* Device Reset Asserted */
/* Extended Interrupt Cause Set */
/* E1000_EITR_CNT_IGNR is only for 82576 and newer */
diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.c b/drivers/net/ethernet/intel/igb/e1000_mac.c
index fa3dfafd2bb1..2bcce6eef0c7 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mac.c
+++ b/drivers/net/ethernet/intel/igb/e1000_mac.c
@@ -1581,7 +1581,7 @@ s32 igb_disable_pcie_master(struct e1000_hw *hw)
* igb_validate_mdi_setting - Verify MDI/MDIx settings
* @hw: pointer to the HW structure
*
- * Verify that when not using auto-negotitation that MDI/MDIx is correctly
+ * Verify that when not using auto-negotiation that MDI/MDIx is correctly
* set, which is forced to MDI mode only.
**/
s32 igb_validate_mdi_setting(struct e1000_hw *hw)
diff --git a/drivers/net/ethernet/intel/igb/e1000_mbx.h b/drivers/net/ethernet/intel/igb/e1000_mbx.h
index 178e60ec71d4..9e44527f5eea 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mbx.h
+++ b/drivers/net/ethernet/intel/igb/e1000_mbx.h
@@ -30,7 +30,7 @@
/* Indicates that VF is still clear to send requests */
#define E1000_VT_MSGTYPE_CTS 0x20000000
#define E1000_VT_MSGINFO_SHIFT 16
-/* bits 23:16 are used for exra info for certain messages */
+/* bits 23:16 are used for extra info for certain messages */
#define E1000_VT_MSGINFO_MASK (0xFF << E1000_VT_MSGINFO_SHIFT)
#define E1000_VF_RESET 0x01 /* VF requests reset */
diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.c b/drivers/net/ethernet/intel/igb/e1000_nvm.c
index c8638502c2be..cf4e5d0e9417 100644
--- a/drivers/net/ethernet/intel/igb/e1000_nvm.c
+++ b/drivers/net/ethernet/intel/igb/e1000_nvm.c
@@ -405,7 +405,7 @@ s32 igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
* Writes data to EEPROM at offset using SPI interface.
*
* If e1000_update_nvm_checksum is not called after this function , the
- * EEPROM will most likley contain an invalid checksum.
+ * EEPROM will most likely contain an invalid checksum.
**/
s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
{
--
2.47.1
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH net-next 12/15] igc: fix typos in comments
2026-03-30 23:02 [PATCH net-next 00/15][pull request] Intel Wired LAN Driver Updates 2026-03-30 (igc, igb, ice) Tony Nguyen
` (10 preceding siblings ...)
2026-03-30 23:02 ` [PATCH net-next 11/15] igb: fix typos in comments Tony Nguyen
@ 2026-03-30 23:02 ` Tony Nguyen
2026-03-30 23:02 ` [PATCH net-next 13/15] ice: add support for unmanaged DPLL on E830 NIC Tony Nguyen
` (2 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Maximilian Pezzullo, anthony.l.nguyen, Aleksandr Loktionov,
Joe Damato
From: Maximilian Pezzullo <maximilianpezzullo@gmail.com>
Fix spelling errors in code comments:
- igc_diag.c: 'autonegotioation' -> 'autonegotiation'
- igc_main.c: 'revisons' -> 'revisions' (two occurrences)
Signed-off-by: Maximilian Pezzullo <maximilianpezzullo@gmail.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Joe Damato <joe@dama.to>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igc/igc_diag.c | 2 +-
drivers/net/ethernet/intel/igc/igc_main.c | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/intel/igc/igc_diag.c b/drivers/net/ethernet/intel/igc/igc_diag.c
index a43d7244ee70..031561fdce49 100644
--- a/drivers/net/ethernet/intel/igc/igc_diag.c
+++ b/drivers/net/ethernet/intel/igc/igc_diag.c
@@ -172,7 +172,7 @@ bool igc_link_test(struct igc_adapter *adapter, u64 *data)
*data = 0;
- /* add delay to give enough time for autonegotioation to finish */
+ /* add delay to give enough time for autonegotiation to finish */
ssleep(5);
link_up = igc_has_link(adapter);
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index ebd831a4ff53..cad5a26cc84d 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -1794,7 +1794,7 @@ static const enum pkt_hash_types igc_rss_type_table[IGC_RSS_TYPE_MAX_TABLE] = {
[IGC_RSS_TYPE_HASH_UDP_IPV6_EX] = PKT_HASH_TYPE_L4,
[10] = PKT_HASH_TYPE_NONE, /* RSS Type above 9 "Reserved" by HW */
[11] = PKT_HASH_TYPE_NONE, /* keep array sized for SW bit-mask */
- [12] = PKT_HASH_TYPE_NONE, /* to handle future HW revisons */
+ [12] = PKT_HASH_TYPE_NONE, /* to handle future HW revisions */
[13] = PKT_HASH_TYPE_NONE,
[14] = PKT_HASH_TYPE_NONE,
[15] = PKT_HASH_TYPE_NONE,
@@ -7040,7 +7040,7 @@ static enum xdp_rss_hash_type igc_xdp_rss_type[IGC_RSS_TYPE_MAX_TABLE] = {
[IGC_RSS_TYPE_HASH_UDP_IPV6_EX] = XDP_RSS_TYPE_L4_IPV6_UDP_EX,
[10] = XDP_RSS_TYPE_NONE, /* RSS Type above 9 "Reserved" by HW */
[11] = XDP_RSS_TYPE_NONE, /* keep array sized for SW bit-mask */
- [12] = XDP_RSS_TYPE_NONE, /* to handle future HW revisons */
+ [12] = XDP_RSS_TYPE_NONE, /* to handle future HW revisions */
[13] = XDP_RSS_TYPE_NONE,
[14] = XDP_RSS_TYPE_NONE,
[15] = XDP_RSS_TYPE_NONE,
--
2.47.1
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH net-next 13/15] ice: add support for unmanaged DPLL on E830 NIC
2026-03-30 23:02 [PATCH net-next 00/15][pull request] Intel Wired LAN Driver Updates 2026-03-30 (igc, igb, ice) Tony Nguyen
` (11 preceding siblings ...)
2026-03-30 23:02 ` [PATCH net-next 12/15] igc: " Tony Nguyen
@ 2026-03-30 23:02 ` Tony Nguyen
2026-04-02 10:26 ` [net-next,13/15] " Paolo Abeni
2026-03-30 23:02 ` [PATCH net-next 14/15] ice: mention fw_activate action along with devlink reload Tony Nguyen
2026-03-30 23:02 ` [PATCH net-next 15/15] ice: dpll: Fix compilation warning Tony Nguyen
14 siblings, 1 reply; 22+ messages in thread
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Arkadiusz Kubalewski, anthony.l.nguyen, richardcochran, corbet,
linux-doc, horms, aleksandr.loktionov, przemyslaw.kitszel,
vgrinber, Paul Menzel, Grzegorz Nitka, Sunitha Mekala
From: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Hardware variants of E830 may support an unmanaged DPLL where the
configuration is hardcoded within the hardware and firmware, meaning
users cannot modify settings. However, users are able to check the DPLL
lock status and obtain configuration information through the Linux DPLL
and devlink health subsystem.
Availability of 'loss of lock' health status code determines if such
support is available, if true, register single DPLL device with 1 input
and 1 output and provide hardcoded/read only properties of a pin and
DPLL device. User is only allowed to check DPLL device status and receive
notifications on DPLL lock status change.
When present, the DPLL device locks to an external signal provided
through the PCIe/OCP pin. The expected input signal is 1PPS
(1 Pulse Per Second) embedded on a 10MHz reference clock.
The DPLL produces output:
- for MAC (Media Access Control) & PHY (Physical Layer) clocks,
- 1PPS for synchronization of onboard PHC (Precision Hardware Clock) timer.
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Signed-off-by: Grzegorz Nitka <grzegorz.nitka@intel.com>
Signed-off-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Tested-by: Sunitha Mekala <sunithax.d.mekala@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
.../device_drivers/ethernet/intel/ice.rst | 83 +++++
.../net/ethernet/intel/ice/devlink/health.c | 4 +
.../net/ethernet/intel/ice/ice_adminq_cmd.h | 12 +
drivers/net/ethernet/intel/ice/ice_common.c | 136 ++++++++
drivers/net/ethernet/intel/ice/ice_common.h | 8 +
drivers/net/ethernet/intel/ice/ice_dpll.c | 302 ++++++++++++++++--
drivers/net/ethernet/intel/ice/ice_dpll.h | 10 +
drivers/net/ethernet/intel/ice/ice_main.c | 11 +-
drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 46 +++
drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 1 +
10 files changed, 592 insertions(+), 21 deletions(-)
diff --git a/Documentation/networking/device_drivers/ethernet/intel/ice.rst b/Documentation/networking/device_drivers/ethernet/intel/ice.rst
index 0bca293cf9cb..09877066b031 100644
--- a/Documentation/networking/device_drivers/ethernet/intel/ice.rst
+++ b/Documentation/networking/device_drivers/ethernet/intel/ice.rst
@@ -941,6 +941,89 @@ To see input signal on those PTP pins, you need to configure DPLL properly.
Output signal is only visible on DPLL and to send it to the board SMA/U.FL pins,
DPLL output pins have to be manually configured.
+Unmanaged DPLL Support
+----------------------
+Hardware variants of E830 may support an unmanaged DPLL:
+
+- Intel(R) Ethernet Network Adapter E830-XXVDA8F for OCP 3.0,
+
+- Intel(R) Ethernet Network Adapter E830-XXVDA4F.
+
+In the case of the unmanaged DPLL, the configuration is hardcoded within the
+hardware and firmware, meaning users cannot modify settings. However,
+users can check the DPLL lock status and obtain configuration information
+through the Linux DPLL subsystem.
+
+When present, the DPLL device locks to an external signal provided through the
+PCIe/OCP pin. The expected input signal is 1PPS (1 Pulse Per Second) embedded
+on a 10MHz reference clock.
+The DPLL produces output:
+
+- for MAC (Media Access Control) & PHY (Physical Layer) clocks,
+
+- 1PPS for synchronization of onboard PHC (Precision Hardware Clock) timer.
+
+Requirements: The Linux kernel must have support for both the DPLL Subsystem
+and the Embedded Sync patch series.
+
+Example output of querying the Linux DPLL subsystem can be found below.
+
+.. code-block:: console
+ :caption: Dumping the DPLL pins
+
+ $ <ynl> --spec Documentation/netlink/specs/dpll.yaml --dump pin-get
+ [{'board-label': '1588-TIME_SYNC',
+ 'capabilities': set(),
+ 'clock-id': 282574471561216,
+ 'esync-frequency': 1,
+ 'esync-frequency-supported': [{'frequency-max': 1, 'frequency-min': 1}],
+ 'esync-pulse': 25,
+ 'frequency': 10000000,
+ 'id': 13,
+ 'module-name': 'ice',
+ 'parent-device': [{'direction': 'input',
+ 'parent-id': 6,
+ 'state': 'connected'}],
+ 'phase-adjust-max': 0,
+ 'phase-adjust-min': 0,
+ 'type': 'ext'},
+ {'board-label': 'MAC-PHY-CLK',
+ 'capabilities': set(),
+ 'clock-id': 282574471561216,
+ 'frequency': 156250000,
+ 'id': 14,
+ 'module-name': 'ice',
+ 'parent-device': [{'direction': 'output',
+ 'parent-id': 6,
+ 'state': 'connected'}],
+ 'phase-adjust-max': 0,
+ 'phase-adjust-min': 0,
+ 'type': 'synce-eth-port'},
+ {'board-label': '1588-TIME_REF',
+ 'capabilities': set(),
+ 'clock-id': 282574471561216,
+ 'frequency': 1,
+ 'id': 15,
+ 'module-name': 'ice',
+ 'parent-device': [{'direction': 'output',
+ 'parent-id': 6,
+ 'state': 'connected'}],
+ 'phase-adjust-max': 0,
+ 'phase-adjust-min': 0,
+ 'type': 'int-oscillator'}]
+
+.. code-block:: console
+ :caption: Dumping the DPLL devices
+
+ $ <ynl> --spec Documentation/netlink/specs/dpll.yaml --dump device-get
+ [{'clock-id': 282574471561216,
+ 'id': 6,
+ 'lock-status': 'locked',
+ 'mode': 'manual',
+ 'mode-supported': ['manual'],
+ 'module-name': 'ice',
+ 'type': 'pps'}]
+
GNSS module
-----------
Requires kernel compiled with CONFIG_GNSS=y or CONFIG_GNSS=m.
diff --git a/drivers/net/ethernet/intel/ice/devlink/health.c b/drivers/net/ethernet/intel/ice/devlink/health.c
index 8e9a8a8178d4..31e6c5107c97 100644
--- a/drivers/net/ethernet/intel/ice/devlink/health.c
+++ b/drivers/net/ethernet/intel/ice/devlink/health.c
@@ -101,6 +101,8 @@ static const struct ice_health_status ice_health_status_lookup[] = {
"Supplied MIB file is invalid. DCB reverted to default configuration.",
"Disable FW-LLDP and check DCBx system configuration.",
{ice_port_number_label, "MIB ID"}},
+ {ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK, "Local DPLL lock status",
+ NULL,},
};
static int ice_health_status_lookup_compare(const void *a, const void *b)
@@ -242,6 +244,8 @@ void ice_process_health_status_event(struct ice_pf *pf, struct ice_rq_event_info
pf->health_reporters.fw_status = *health_info;
devlink_health_report(pf->health_reporters.fw,
"FW syndrome reported", NULL);
+ if (status_code == ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK)
+ ice_dpll_lock_state_set_unmanaged(pf, health_info, true);
break;
case ICE_AQC_HEALTH_STATUS_PF:
case ICE_AQC_HEALTH_STATUS_PORT:
diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
index 859e9c66f3e7..3f8c1b8befc3 100644
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
@@ -1498,6 +1498,7 @@ struct ice_aqc_get_link_topo {
#define ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575 0x21
#define ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL30632_80032 0x24
#define ICE_AQC_GET_LINK_TOPO_NODE_NR_SI5383_5384 0x25
+#define ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL80640 0x27
#define ICE_AQC_GET_LINK_TOPO_NODE_NR_E822_PHY 0x30
#define ICE_AQC_GET_LINK_TOPO_NODE_NR_C827 0x31
#define ICE_AQC_GET_LINK_TOPO_NODE_NR_GEN_CLK_MUX 0x47
@@ -2481,11 +2482,14 @@ enum ice_aqc_health_status {
ICE_AQC_HEALTH_STATUS_ERR_BMC_RESET = 0x50B,
ICE_AQC_HEALTH_STATUS_ERR_LAST_MNG_FAIL = 0x50C,
ICE_AQC_HEALTH_STATUS_ERR_RESOURCE_ALLOC_FAIL = 0x50D,
+ ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK = 0x601,
ICE_AQC_HEALTH_STATUS_ERR_FW_LOOP = 0x1000,
ICE_AQC_HEALTH_STATUS_ERR_FW_PFR_FAIL = 0x1001,
ICE_AQC_HEALTH_STATUS_ERR_LAST_FAIL_AQ = 0x1002,
};
+#define ICE_AQC_HEALTH_STATUS_CODE_NUM 64
+
/* Get Health Status (indirect 0xFF22) */
struct ice_aqc_get_health_status {
__le16 health_status_count;
@@ -2512,6 +2516,13 @@ struct ice_aqc_health_status_elem {
__le32 internal_data2;
};
+/* Get Health Status response buffer entry, (0xFF21)
+ * repeated per reported health status
+ */
+struct ice_aqc_health_status_supp_elem {
+ __le16 health_status_code;
+};
+
/* Admin Queue command opcodes */
enum ice_adminq_opc {
/* AQ commands */
@@ -2675,6 +2686,7 @@ enum ice_adminq_opc {
/* System Diagnostic commands */
ice_aqc_opc_set_health_status_cfg = 0xFF20,
+ ice_aqc_opc_get_supported_health_status_codes = 0xFF21,
ice_aqc_opc_get_health_status = 0xFF22,
/* FW Logging Commands */
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index ce11fea122d0..0e246d193712 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -3050,6 +3050,29 @@ bool ice_is_cgu_in_netlist(struct ice_hw *hw)
return false;
}
+/**
+ * ice_is_unmanaged_cgu_in_netlist - check for unmanaged CGU presence
+ * @hw: pointer to the hw struct
+ *
+ * Check if the unmanaged Clock Generation Unit (CGU) device is present in the netlist.
+ * Save the CGU part number in the hw structure for later use.
+ * Return:
+ * * true - unmanaged cgu is present
+ * * false - unmanaged cgu is not present
+ */
+bool ice_is_unmanaged_cgu_in_netlist(struct ice_hw *hw)
+{
+ if (!ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL,
+ ICE_AQC_LINK_TOPO_NODE_CTX_GLOBAL,
+ ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL80640,
+ NULL)) {
+ hw->cgu_part_number = ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL80640;
+ return true;
+ }
+
+ return false;
+}
+
/**
* ice_is_gps_in_netlist
* @hw: pointer to the hw struct
@@ -6312,6 +6335,119 @@ bool ice_is_fw_health_report_supported(struct ice_hw *hw)
ICE_FW_API_HEALTH_REPORT_PATCH);
}
+/**
+ * ice_aq_get_health_status_supported - get supported health status codes
+ * @hw: pointer to the HW struct
+ * @buff: pointer to buffer where health status elements will be stored
+ * @num: number of health status elements buffer can hold
+ *
+ * Return:
+ * * 0 - success,
+ * * negative - AQ error code.
+ */
+static int
+ice_aq_get_health_status_supported(struct ice_hw *hw,
+ struct ice_aqc_health_status_supp_elem *buff,
+ int num)
+{
+ u16 code = ice_aqc_opc_get_supported_health_status_codes;
+ struct libie_aq_desc desc;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, code);
+
+ return ice_aq_send_cmd(hw, &desc, buff, num * sizeof(*buff), NULL);
+}
+
+/**
+ * ice_aq_get_health_status - get current health status array from the firmware
+ * @hw: pointer to the HW struct
+ * @buff: pointer to buffer where health status elements will be stored
+ * @num: number of health status elements buffer can hold
+ *
+ * Return:
+ * * 0 - success,
+ * * negative - AQ error code.
+ */
+int ice_aq_get_health_status(struct ice_hw *hw,
+ struct ice_aqc_health_status_elem *buff, int num)
+{
+ struct libie_aq_desc desc;
+
+ ice_fill_dflt_direct_cmd_desc(&desc,
+ ice_aqc_opc_get_health_status);
+
+ return ice_aq_send_cmd(hw, &desc, buff, num * sizeof(*buff), NULL);
+}
+
+/**
+ * ice_is_health_status_code_supported - check if health status code is supported
+ * @hw: pointer to the hardware structure
+ * @code: health status code to check
+ * @supported: pointer to boolean result
+ *
+ * Return: 0 on success, negative error code otherwise
+ */
+int ice_is_health_status_code_supported(struct ice_hw *hw, u16 code,
+ bool *supported)
+{
+ const int BUFF_SIZE = ICE_AQC_HEALTH_STATUS_CODE_NUM;
+ struct ice_aqc_health_status_supp_elem *buff;
+ int ret;
+
+ *supported = false;
+ buff = kzalloc_objs(*buff, BUFF_SIZE);
+ if (!buff)
+ return -ENOMEM;
+ ret = ice_aq_get_health_status_supported(hw, buff, BUFF_SIZE);
+ if (ret)
+ goto free_buff;
+ for (int i = 0; i < BUFF_SIZE && buff[i].health_status_code; i++)
+ if (le16_to_cpu(buff[i].health_status_code) == code) {
+ *supported = true;
+ break;
+ }
+
+free_buff:
+ kfree(buff);
+ return ret;
+}
+
+/**
+ * ice_get_last_health_status_code - get last health status for given code
+ * @hw: pointer to the hardware structure
+ * @out: pointer to the health status struct to be filled
+ * @code: health status code to check
+ *
+ * Return: 0 on success, negative error code otherwise
+ */
+int ice_get_last_health_status_code(struct ice_hw *hw,
+ struct ice_aqc_health_status_elem *out,
+ u16 code)
+{
+ const int BUFF_SIZE = ICE_AQC_HEALTH_STATUS_CODE_NUM;
+ struct ice_aqc_health_status_elem *buff;
+ int ret, last_status = -1;
+
+ buff = kzalloc_objs(*buff, BUFF_SIZE);
+ if (!buff)
+ return -ENOMEM;
+ ret = ice_aq_get_health_status(hw, buff, BUFF_SIZE);
+ if (ret)
+ goto free_buff;
+ for (int i = 0; i < BUFF_SIZE && buff[i].health_status_code; i++)
+ if (le16_to_cpu(buff[i].health_status_code) == code)
+ last_status = i;
+
+ if (last_status >= 0)
+ memcpy(out, &buff[last_status], sizeof(*out));
+ else
+ memset(out, 0, sizeof(*out));
+
+free_buff:
+ kfree(buff);
+ return ret;
+}
+
/**
* ice_aq_set_health_status_cfg - Configure FW health events
* @hw: pointer to the HW struct
diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h
index e700ac0dc347..cbecee66e2a7 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.h
+++ b/drivers/net/ethernet/intel/ice/ice_common.h
@@ -162,6 +162,7 @@ ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,
bool ice_is_phy_rclk_in_netlist(struct ice_hw *hw);
bool ice_is_clock_mux_in_netlist(struct ice_hw *hw);
bool ice_is_cgu_in_netlist(struct ice_hw *hw);
+bool ice_is_unmanaged_cgu_in_netlist(struct ice_hw *hw);
bool ice_is_gps_in_netlist(struct ice_hw *hw);
int
ice_aq_get_netlist_node(struct ice_hw *hw, struct ice_aqc_get_link_topo *cmd,
@@ -188,6 +189,13 @@ ice_get_link_default_override(struct ice_link_default_override_tlv *ldo,
struct ice_port_info *pi);
bool ice_is_phy_caps_an_enabled(struct ice_aqc_get_phy_caps_data *caps);
bool ice_is_fw_health_report_supported(struct ice_hw *hw);
+int ice_aq_get_health_status(struct ice_hw *hw,
+ struct ice_aqc_health_status_elem *buff, int num);
+int ice_is_health_status_code_supported(struct ice_hw *hw, u16 code,
+ bool *supported);
+int ice_get_last_health_status_code(struct ice_hw *hw,
+ struct ice_aqc_health_status_elem *out,
+ u16 code);
int ice_aq_set_health_status_cfg(struct ice_hw *hw, u8 event_source);
int ice_aq_get_phy_equalization(struct ice_hw *hw, u16 data_in, u16 op_code,
u8 serdes_num, int *output);
diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c
index 62f75701d652..2a9eb233dbf4 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.c
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.c
@@ -18,6 +18,8 @@
#define ICE_DPLL_SW_PIN_INPUT_BASE_SFP 4
#define ICE_DPLL_SW_PIN_INPUT_BASE_QSFP 6
#define ICE_DPLL_SW_PIN_OUTPUT_BASE 0
+#define ICE_DPLL_HEALTH_STATUS_LOCKED 1
+#define ICE_DPLL_HEALTH_STATUS_UNLOCKED 0
#define ICE_DPLL_PIN_SW_INPUT_ABS(in_idx) \
(ICE_DPLL_SW_PIN_INPUT_BASE_SFP + (in_idx))
@@ -80,6 +82,10 @@ static const struct dpll_pin_frequency ice_esync_range[] = {
DPLL_PIN_FREQUENCY_RANGE(0, DPLL_PIN_FREQUENCY_1_HZ),
};
+static const struct dpll_pin_frequency ice_esync_range_unmanaged[] = {
+ DPLL_PIN_FREQUENCY_1PPS,
+};
+
/**
* ice_dpll_is_sw_pin - check if given pin shall be controlled by SW
* @pf: private board structure
@@ -1089,9 +1095,11 @@ ice_dpll_pin_state_get(const struct dpll_pin *pin, void *pin_priv,
return -EBUSY;
mutex_lock(&pf->dplls.lock);
- ret = ice_dpll_pin_state_update(pf, p, pin_type, extack);
- if (ret)
- goto unlock;
+ if (!pf->dplls.unmanaged) {
+ ret = ice_dpll_pin_state_update(pf, p, pin_type, extack);
+ if (ret)
+ goto unlock;
+ }
if (pin_type == ICE_DPLL_PIN_TYPE_INPUT ||
pin_type == ICE_DPLL_PIN_TYPE_OUTPUT)
*state = p->state[d->dpll_idx];
@@ -2151,9 +2159,14 @@ ice_dpll_input_esync_get(const struct dpll_pin *pin, void *pin_priv,
mutex_unlock(&pf->dplls.lock);
return -EOPNOTSUPP;
}
- esync->range = ice_esync_range;
- esync->range_num = ARRAY_SIZE(ice_esync_range);
- if (p->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN) {
+ if (pf->dplls.unmanaged) {
+ esync->range = ice_esync_range_unmanaged;
+ esync->range_num = ARRAY_SIZE(ice_esync_range_unmanaged);
+ } else {
+ esync->range = ice_esync_range;
+ esync->range_num = ARRAY_SIZE(ice_esync_range);
+ }
+ if (p->flags[0] & ICE_DPLL_IN_ESYNC_ENABLED) {
esync->freq = DPLL_PIN_FREQUENCY_1_HZ;
esync->pulse = ICE_DPLL_PIN_ESYNC_PULSE_HIGH_PERCENT;
} else {
@@ -2583,6 +2596,21 @@ static const struct dpll_pin_ops ice_dpll_output_ops = {
.esync_get = ice_dpll_output_esync_get,
};
+static const struct dpll_pin_ops ice_dpll_input_unmanaged_ops = {
+ .frequency_get = ice_dpll_input_frequency_get,
+ .direction_get = ice_dpll_input_direction,
+ .state_on_dpll_get = ice_dpll_input_state_get,
+#if defined(HAVE_DPLL_ESYNC)
+ .esync_get = ice_dpll_input_esync_get,
+#endif /* HAVE_DPLL_ESYNC */
+};
+
+static const struct dpll_pin_ops ice_dpll_output_unmanaged_ops = {
+ .frequency_get = ice_dpll_output_frequency_get,
+ .direction_get = ice_dpll_output_direction,
+ .state_on_dpll_get = ice_dpll_output_state_get,
+};
+
static const struct dpll_device_ops ice_dpll_ops = {
.lock_status_get = ice_dpll_lock_status_get,
.mode_get = ice_dpll_mode_get,
@@ -3148,12 +3176,15 @@ ice_dpll_init_direct_pins(struct ice_pf *pf, bool cgu,
int ret;
ret = ice_dpll_get_pins(pf, pins, start_idx, count, pf->dplls.clock_id);
- if (ret)
+ if (!cgu || ret)
return ret;
- if (cgu) {
+
+ if (first) {
ret = ice_dpll_register_pins(first, pins, ops, count);
if (ret)
goto release_pins;
+ }
+ if (second) {
ret = ice_dpll_register_pins(second, pins, ops, count);
if (ret)
goto unregister_first;
@@ -3162,7 +3193,8 @@ ice_dpll_init_direct_pins(struct ice_pf *pf, bool cgu,
return 0;
unregister_first:
- ice_dpll_unregister_pins(first, pins, ops, count);
+ if (first)
+ ice_dpll_unregister_pins(first, pins, ops, count);
release_pins:
ice_dpll_release_pins(pins, count);
return ret;
@@ -3419,6 +3451,18 @@ static void ice_dpll_deinit_pins(struct ice_pf *pf, bool cgu)
struct ice_dpll *de = &d->eec;
struct ice_dpll *dp = &d->pps;
+ if (d->unmanaged) {
+ ice_dpll_unregister_pins(dp->dpll, inputs,
+ &ice_dpll_input_unmanaged_ops,
+ num_inputs);
+ ice_dpll_unregister_pins(dp->dpll, outputs,
+ &ice_dpll_output_unmanaged_ops,
+ num_outputs);
+ ice_dpll_release_pins(inputs, num_inputs);
+ ice_dpll_release_pins(outputs, num_outputs);
+ return;
+ }
+
ice_dpll_deinit_rclk_pin(pf);
if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825)
ice_dpll_deinit_fwnode_pins(pf, pf->dplls.inputs, 0);
@@ -3603,23 +3647,29 @@ static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu)
const struct dpll_pin_ops *input_ops;
int ret, count;
- input_ops = &ice_dpll_input_ops;
- output_ops = &ice_dpll_output_ops;
+ if (!pf->dplls.unmanaged) {
+ input_ops = &ice_dpll_input_ops;
+ output_ops = &ice_dpll_output_ops;
+ } else {
+ input_ops = &ice_dpll_input_unmanaged_ops;
+ output_ops = &ice_dpll_output_unmanaged_ops;
+ }
ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.inputs, 0,
pf->dplls.num_inputs, input_ops,
- pf->dplls.eec.dpll,
- pf->dplls.pps.dpll);
+ pf->dplls.eec.dpll, pf->dplls.pps.dpll);
if (ret)
return ret;
count = pf->dplls.num_inputs;
- if (cgu) {
+ if (cgu || pf->dplls.unmanaged) {
ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.outputs,
count, pf->dplls.num_outputs,
output_ops, pf->dplls.eec.dpll,
pf->dplls.pps.dpll);
if (ret)
goto deinit_inputs;
+ if (pf->dplls.unmanaged)
+ return 0;
count += pf->dplls.num_outputs;
if (!pf->dplls.generic) {
ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.sma,
@@ -3732,7 +3782,8 @@ ice_dpll_init_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu,
if (type == DPLL_TYPE_PPS && ice_dpll_is_pps_phase_monitor(pf))
ops = &ice_dpll_pom_ops;
- ice_dpll_update_state(pf, d, true);
+ if (!pf->dplls.unmanaged)
+ ice_dpll_update_state(pf, d, true);
ret = dpll_device_register(d->dpll, type, ops, d);
if (ret) {
dpll_device_put(d->dpll, &d->tracker);
@@ -3759,6 +3810,33 @@ static void ice_dpll_deinit_worker(struct ice_pf *pf)
kthread_destroy_worker(d->kworker);
}
+/**
+ * ice_dpll_pin_freq_info - find pin frequency from supported ones
+ * @hw: pointer to the hardware structure
+ * @pin_idx: pin index
+ * @input: if input pin
+ *
+ * This function searches through the array of supported frequencies for a
+ * DPLL pin and returns single frequency pin is capable, if pin support only
+ * one frequency. Shall be used only for dpll with driver hardcoded frequency.
+ *
+ * Return:
+ * * 0 - failure, pin uses multiple frequencies,
+ * * frequency - success.
+ */
+static u64 ice_dpll_pin_freq_info(struct ice_hw *hw, u8 pin_idx, bool input)
+{
+ struct dpll_pin_frequency *freqs;
+ u8 freq_num;
+
+ /* Get supported frequencies for this pin */
+ freqs = ice_cgu_get_pin_freq_supp(hw, pin_idx, input, &freq_num);
+ if (!freqs || freq_num != 1 || freqs[0].min != freqs[0].max)
+ return 0;
+
+ return freqs[0].min;
+}
+
/**
* ice_dpll_init_worker - Initialize DPLLs periodic worker
* @pf: board private structure
@@ -3918,6 +3996,15 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf,
pins[i].prop.board_label = ice_cgu_get_pin_name(hw, i, input);
pins[i].prop.type = ice_cgu_get_pin_type(hw, i, input);
if (input) {
+ if (pf->dplls.unmanaged) {
+ pins[i].freq = ice_dpll_pin_freq_info(hw, i,
+ input);
+ pins[i].state[0] = DPLL_PIN_STATE_CONNECTED;
+ pins[i].status =
+ ICE_AQC_GET_CGU_IN_CFG_STATUS_ESYNC_CAP;
+ pins[i].flags[0] = ICE_DPLL_IN_ESYNC_ENABLED;
+ continue;
+ }
ret = ice_aq_get_cgu_ref_prio(hw, de->dpll_idx, i,
&de->input_prio[i]);
if (ret)
@@ -3931,6 +4018,12 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf,
if (ice_dpll_is_sw_pin(pf, i, true))
pins[i].hidden = true;
} else {
+ if (pf->dplls.unmanaged) {
+ pins[i].freq = ice_dpll_pin_freq_info(hw, i,
+ input);
+ pins[i].state[0] = DPLL_PIN_STATE_CONNECTED;
+ continue;
+ }
ret = ice_cgu_get_output_pin_state_caps(hw, i, &caps);
if (ret)
return ret;
@@ -3948,10 +4041,13 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf,
pins[i].prop.freq_supported_num = freq_supp_num;
pins[i].pf = pf;
}
- if (input)
+ if (input && !pf->dplls.unmanaged) {
ret = ice_dpll_init_ref_sync_inputs(pf);
+ if (ret)
+ return ret;
+ }
- return ret;
+ return 0;
}
/**
@@ -4144,7 +4240,6 @@ static int ice_dpll_init_info_e825c(struct ice_pf *pf)
d->clock_id = ice_generate_clock_id(pf);
d->num_inputs = ICE_SYNCE_CLK_NUM;
-
d->inputs = kzalloc_objs(*d->inputs, d->num_inputs);
if (!d->inputs)
return -ENOMEM;
@@ -4169,6 +4264,82 @@ static int ice_dpll_init_info_e825c(struct ice_pf *pf)
return ret;
}
+/**
+ * ice_dpll_lock_state_init_unmanaged - initialize lock state for unmanaged dpll
+ * @pf: board private structure
+ *
+ * Initialize the lock state for unmanaged DPLL by checking health status.
+ * For unmanaged DPLL, we rely on hardware autonomous operation.
+ *
+ * Return:
+ * * 0 - success
+ * * negative - init failure reason
+ */
+static int ice_dpll_lock_state_init_unmanaged(struct ice_pf *pf)
+{
+ u16 code = ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK;
+ struct ice_aqc_health_status_elem buff;
+ int ret;
+
+ ret = ice_get_last_health_status_code(&pf->hw, &buff, code);
+ if (ret)
+ return ret;
+ ice_dpll_lock_state_set_unmanaged(pf, &buff, false);
+
+ return ret;
+}
+
+/**
+ * ice_dpll_init_info_unmanaged - init dpll information for unmanaged dpll
+ * @pf: board private structure
+ *
+ * Acquire (from HW) and set basic dpll information (on pf->dplls struct).
+ * For unmanaged dpll mode.
+ *
+ * Return:
+ * * 0 - success
+ * * negative - init failure reason
+ */
+static int ice_dpll_init_info_unmanaged(struct ice_pf *pf)
+{
+ struct ice_dplls *d = &pf->dplls;
+ int ret;
+
+ d->clock_id = ice_generate_clock_id(pf);
+ d->num_inputs = ice_cgu_get_pin_num(&pf->hw, true);
+ d->num_outputs = ice_cgu_get_pin_num(&pf->hw, false);
+ ret = ice_dpll_lock_state_init_unmanaged(pf);
+ if (ret)
+ return ret;
+ d->inputs = kzalloc_objs(*d->inputs, d->num_inputs);
+ if (!d->inputs)
+ return -ENOMEM;
+
+ ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_INPUT);
+ if (ret)
+ goto deinit_info;
+
+ d->outputs = kzalloc_objs(*d->outputs, d->num_outputs);
+ if (!d->outputs) {
+ ret = -ENOMEM;
+ goto deinit_info;
+ }
+
+ ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_OUTPUT);
+ if (ret)
+ goto deinit_info;
+
+ d->pps.mode = DPLL_MODE_MANUAL;
+ dev_dbg(ice_pf_to_dev(pf), "%s - success, inputs:%u, outputs:%u\n",
+ __func__, d->num_inputs, d->num_outputs);
+ return 0;
+deinit_info:
+ dev_err(ice_pf_to_dev(pf), "%s - fail: d->inputs:%p, d->outputs:%p\n",
+ __func__, d->inputs, d->outputs);
+ ice_dpll_deinit_info(pf);
+ return ret;
+}
+
/**
* ice_dpll_init_info - prepare pf's dpll information structure
* @pf: board private structure
@@ -4268,6 +4439,42 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu)
return ret;
}
+/**
+ * ice_dpll_lock_state_set_unmanaged - determine lock state from health status
+ * @pf: board private structure
+ * @buff: health status buffer
+ * @notify: if true, notify dpll device
+ *
+ * Set unmanaged dpll lock state based on health status code and internal data.
+ * Context: Acquires and releases pf->dplls.lock (must release before notify
+ * if called).
+ */
+void ice_dpll_lock_state_set_unmanaged(struct ice_pf *pf,
+ const struct ice_aqc_health_status_elem *buff,
+ bool notify)
+{
+ u32 internal_data = le32_to_cpu(buff->internal_data1);
+ struct ice_dpll *d = &pf->dplls.pps;
+
+ if (!ice_pf_src_tmr_owned(pf))
+ return;
+
+ mutex_lock(&pf->dplls.lock);
+ if (buff->health_status_code == 0 ||
+ internal_data == ICE_DPLL_HEALTH_STATUS_LOCKED)
+ d->dpll_state = DPLL_LOCK_STATUS_LOCKED;
+ else
+ d->dpll_state = DPLL_LOCK_STATUS_UNLOCKED;
+
+ if (d->prev_dpll_state == d->dpll_state)
+ notify = false;
+ else
+ d->prev_dpll_state = d->dpll_state;
+ mutex_unlock(&pf->dplls.lock);
+ if (notify && d->dpll)
+ dpll_device_change_ntf(d->dpll);
+}
+
/**
* ice_dpll_deinit - Disable the driver/HW support for dpll subsystem
* the dpll device.
@@ -4287,15 +4494,55 @@ void ice_dpll_deinit(struct ice_pf *pf)
if (cgu)
ice_dpll_deinit_worker(pf);
- ice_dpll_deinit_pins(pf, cgu);
+ ice_dpll_deinit_pins(pf, cgu || pf->dplls.unmanaged);
if (!IS_ERR_OR_NULL(pf->dplls.pps.dpll))
- ice_dpll_deinit_dpll(pf, &pf->dplls.pps, cgu);
+ ice_dpll_deinit_dpll(pf, &pf->dplls.pps,
+ cgu || pf->dplls.unmanaged);
if (!IS_ERR_OR_NULL(pf->dplls.eec.dpll))
ice_dpll_deinit_dpll(pf, &pf->dplls.eec, cgu);
ice_dpll_deinit_info(pf);
mutex_destroy(&pf->dplls.lock);
}
+/**
+ * ice_dpll_init_unmanaged - initialize support for unmanaged dpll subsystem
+ * @pf: board private structure
+ *
+ * Set up the device dplls for unmanaged mode, register them and pins connected
+ * within Linux dpll subsystem. Allow userspace to obtain state of DPLL.
+ *
+ * Context: Initializes pf->dplls.lock mutex.
+ */
+static void ice_dpll_init_unmanaged(struct ice_pf *pf)
+{
+ struct ice_dplls *d = &pf->dplls;
+ int err;
+
+ if (!ice_pf_src_tmr_owned(pf))
+ return;
+ mutex_init(&d->lock);
+ err = ice_dpll_init_info_unmanaged(pf);
+ if (err)
+ goto err_exit;
+ err = ice_dpll_init_dpll(pf, &pf->dplls.pps, true, DPLL_TYPE_PPS);
+ if (err)
+ goto deinit_info;
+ err = ice_dpll_init_pins(pf, true);
+ if (err)
+ goto deinit_pps;
+ set_bit(ICE_FLAG_DPLL, pf->flags);
+
+ return;
+
+deinit_pps:
+ ice_dpll_deinit_dpll(pf, &pf->dplls.pps, true);
+deinit_info:
+ ice_dpll_deinit_info(pf);
+err_exit:
+ mutex_destroy(&d->lock);
+ dev_warn(ice_pf_to_dev(pf), "DPLLs init failure err:%d\n", err);
+}
+
/**
* ice_dpll_init_e825 - initialize support for dpll subsystem
* @pf: board private structure
@@ -4383,8 +4630,23 @@ static void ice_dpll_init_e810(struct ice_pf *pf)
dev_warn(ice_pf_to_dev(pf), "DPLLs init failure err:%d\n", err);
}
+/**
+ * ice_dpll_init - initialize support for dpll subsystem
+ * @pf: board private structure
+ *
+ * Set up the device dplls, register them and pins connected within Linux dpll
+ * subsystem. Allow userspace to obtain state of DPLL and handling of DPLL
+ * configuration requests.
+ *
+ * Context: Initializes pf->dplls.lock mutex.
+ */
void ice_dpll_init(struct ice_pf *pf)
{
+ if (pf->dplls.unmanaged) {
+ ice_dpll_init_unmanaged(pf);
+ return;
+ }
+
switch (pf->hw.mac_type) {
case ICE_MAC_GENERIC_3K_E825:
ice_dpll_init_e825(pf);
diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.h b/drivers/net/ethernet/intel/ice/ice_dpll.h
index ae42cdea0ee1..2c98b6c6deb0 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.h
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.h
@@ -146,14 +146,22 @@ struct ice_dplls {
s32 output_phase_adj_max;
u32 periodic_counter;
bool generic;
+ bool unmanaged;
};
#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
void ice_dpll_init(struct ice_pf *pf);
void ice_dpll_deinit(struct ice_pf *pf);
+void ice_dpll_lock_state_set_unmanaged(struct ice_pf *pf,
+ const struct ice_aqc_health_status_elem *buff,
+ bool notify);
#else
static inline void ice_dpll_init(struct ice_pf *pf) { }
static inline void ice_dpll_deinit(struct ice_pf *pf) { }
+static inline void
+ice_dpll_lock_state_set_unmanaged(struct ice_pf *pf,
+ const struct ice_aqc_health_status_elem *buff,
+ bool notify) { }
#endif
#endif
@@ -173,3 +181,5 @@ static inline void ice_dpll_deinit(struct ice_pf *pf) { }
#define ICE_CGU_R11_SYNCE_S_BYP_CLK GENMASK(6, 1)
#define ICE_CGU_BYPASS_MUX_OFFSET_E825C 3
+#define ICE_DPLL_UNMANAGED_PIN_NUM 4
+#define ICE_DPLL_IN_ESYNC_ENABLED ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 3c36e3641b9e..325c7f850ff8 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -4787,7 +4787,9 @@ void ice_deinit_dev(struct ice_pf *pf)
static void ice_init_features(struct ice_pf *pf)
{
+ u16 code = ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK;
struct device *dev = ice_pf_to_dev(pf);
+ int err;
if (ice_is_safe_mode(pf))
return;
@@ -4799,8 +4801,15 @@ static void ice_init_features(struct ice_pf *pf)
if (ice_is_feature_supported(pf, ICE_F_GNSS))
ice_gnss_init(pf);
+ /* Initialize unmanaged DPLL detection */
+ err = ice_is_health_status_code_supported(&pf->hw, code,
+ &pf->dplls.unmanaged);
+ if (err || !ice_is_unmanaged_cgu_in_netlist(&pf->hw))
+ pf->dplls.unmanaged = false;
+
if (ice_is_feature_supported(pf, ICE_F_CGU) ||
- ice_is_feature_supported(pf, ICE_F_PHY_RCLK))
+ ice_is_feature_supported(pf, ICE_F_PHY_RCLK) ||
+ pf->dplls.unmanaged)
ice_dpll_init(pf);
/* Note: Flow director init failure is non-fatal to load */
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
index 61c0a0d93ea8..54555d232bd1 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
@@ -20,6 +20,10 @@ static struct dpll_pin_frequency ice_cgu_pin_freq_10_mhz[] = {
DPLL_PIN_FREQUENCY_10MHZ,
};
+static struct dpll_pin_frequency ice_cgu_pin_freq_156_25mhz[] = {
+ DPLL_PIN_FREQUENCY_RANGE(156250000, 156250000),
+};
+
static const struct ice_cgu_pin_desc ice_e810t_sfp_cgu_inputs[] = {
{ "CVL-SDP22", ZL_REF0P, DPLL_PIN_TYPE_INT_OSCILLATOR,
ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common },
@@ -131,6 +135,18 @@ static const struct ice_cgu_pin_desc ice_e823_zl_cgu_outputs[] = {
{ "NONE", ZL_OUT5, 0, 0 },
};
+static const struct ice_cgu_pin_desc ice_e830_unmanaged_inputs[] = {
+ { "1588-TIME_SYNC", 0, DPLL_PIN_TYPE_EXT,
+ ARRAY_SIZE(ice_cgu_pin_freq_10_mhz), ice_cgu_pin_freq_10_mhz },
+};
+
+static const struct ice_cgu_pin_desc ice_e830_unmanaged_outputs[] = {
+ { "MAC-PHY-CLK", 0, DPLL_PIN_TYPE_SYNCE_ETH_PORT,
+ ARRAY_SIZE(ice_cgu_pin_freq_156_25mhz), ice_cgu_pin_freq_156_25mhz },
+ { "1588-TIME_REF", 1, DPLL_PIN_TYPE_INT_OSCILLATOR,
+ ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz},
+};
+
/* Low level functions for interacting with and managing the device clock used
* for the Precision Time Protocol.
*
@@ -5684,6 +5700,24 @@ ice_cgu_get_pin_desc(struct ice_hw *hw, bool input, int *size)
case ICE_DEV_ID_E823C_SGMII:
t = ice_cgu_get_pin_desc_e823(hw, input, size);
break;
+ case ICE_DEV_ID_E830CC_BACKPLANE:
+ case ICE_DEV_ID_E830CC_QSFP56:
+ case ICE_DEV_ID_E830CC_SFP:
+ case ICE_DEV_ID_E830CC_SFP_DD:
+ case ICE_DEV_ID_E830C_BACKPLANE:
+ case ICE_DEV_ID_E830C_QSFP:
+ case ICE_DEV_ID_E830C_SFP:
+ case ICE_DEV_ID_E830_XXV_BACKPLANE:
+ case ICE_DEV_ID_E830_XXV_QSFP:
+ case ICE_DEV_ID_E830_XXV_SFP:
+ if (input) {
+ t = ice_e830_unmanaged_inputs;
+ *size = ARRAY_SIZE(ice_e830_unmanaged_inputs);
+ } else {
+ t = ice_e830_unmanaged_outputs;
+ *size = ARRAY_SIZE(ice_e830_unmanaged_outputs);
+ }
+ break;
default:
break;
}
@@ -5710,6 +5744,18 @@ int ice_cgu_get_num_pins(struct ice_hw *hw, bool input)
return 0;
}
+/**
+ * ice_cgu_get_pin_num - get pin description array size
+ * @hw: pointer to the hw struct
+ * @input: if request is done against input or output pins
+ *
+ * Return: size of pin description array for given hw.
+ */
+int ice_cgu_get_pin_num(struct ice_hw *hw, bool input)
+{
+ return ice_cgu_get_num_pins(hw, input);
+}
+
/**
* ice_cgu_get_pin_type - get pin's type
* @hw: pointer to the hw struct
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
index 9bfd3e79c580..87aa4cfc5a46 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
@@ -356,6 +356,7 @@ int ice_read_sma_ctrl(struct ice_hw *hw, u8 *data);
int ice_write_sma_ctrl(struct ice_hw *hw, u8 data);
int ice_ptp_read_sdp_ac(struct ice_hw *hw, __le16 *entries, uint *num_entries);
int ice_cgu_get_num_pins(struct ice_hw *hw, bool input);
+int ice_cgu_get_pin_num(struct ice_hw *hw, bool input);
enum dpll_pin_type ice_cgu_get_pin_type(struct ice_hw *hw, u8 pin, bool input);
struct dpll_pin_frequency *
ice_cgu_get_pin_freq_supp(struct ice_hw *hw, u8 pin, bool input, u8 *num);
--
2.47.1
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [net-next,13/15] ice: add support for unmanaged DPLL on E830 NIC
2026-03-30 23:02 ` [PATCH net-next 13/15] ice: add support for unmanaged DPLL on E830 NIC Tony Nguyen
@ 2026-04-02 10:26 ` Paolo Abeni
2026-04-03 15:44 ` Tony Nguyen
0 siblings, 1 reply; 22+ messages in thread
From: Paolo Abeni @ 2026-04-02 10:26 UTC (permalink / raw)
To: anthony.l.nguyen
Cc: andriy.shevchenko, pmenzel, aleksandr.loktionov, mika.westerberg,
pabeni, mbloch, saeedm, piotr.kwapulinski, sx.rinitha, kuba,
grzegorz.nitka, netdev, przemyslaw.kitszel, arkadiusz.kubalewski,
tariqt, davem, dima.ruinskiy, bhelgaas, andrew+netdev, lukas,
jacob.e.keller, richardcochran, takkozu, enjuk,
maximilianpezzullo, joe, przemyslaw.korba, leon, vgrinber,
linux-pci, sunithax.d.mekala, corbet, vinicius.gomes,
ilpo.jarvinen, edumazet, linux-doc, kohei.enju, kohei, horms,
avigailx.dahan
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
For local reproduction steps see https://netdev-ai.bots.linux.dev/ai-local.html
---
ice: add support for unmanaged DPLL on E830 NIC
Hardware variants of E830 may support an unmanaged DPLL where the
configuration is hardcoded within the hardware and firmware, meaning
users cannot modify settings. However, users are able to check the DPLL
lock status and obtain configuration information through the Linux DPLL
and devlink health subsystem.
> diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c
> index 62f75701d652..2a9eb233dbf4 100644
> --- a/drivers/net/ethernet/intel/ice/ice_dpll.c
> +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c
[ ... ]
> @@ -3148,12 +3176,15 @@ ice_dpll_init_direct_pins(struct ice_pf *pf, bool cgu,
> int ret;
>
> ret = ice_dpll_get_pins(pf, pins, start_idx, count, pf->dplls.clock_id);
> - if (ret)
> + if (!cgu || ret)
> return ret;
> - if (cgu) {
> +
> + if (first) {
> ret = ice_dpll_register_pins(first, pins, ops, count);
> if (ret)
> goto release_pins;
> + }
> + if (second) {
> ret = ice_dpll_register_pins(second, pins, ops, count);
> if (ret)
> goto unregister_first;
> @@ -3162,7 +3193,8 @@ ice_dpll_init_direct_pins(struct ice_pf *pf, bool cgu,
> return 0;
>
> unregister_first:
> - ice_dpll_unregister_pins(first, pins, ops, count);
> + if (first)
> + ice_dpll_unregister_pins(first, pins, ops, count);
> release_pins:
> ice_dpll_release_pins(pins, count);
> return ret;
NULL checks were added to ice_dpll_init_direct_pins for handling unmanaged
DPLL initialization where only one DPLL device is active. However, is the
corresponding cleanup function ice_dpll_deinit_direct_pins missing the same
NULL checks?
In unmanaged mode, only pf->dplls.pps.dpll is initialized while
pf->dplls.eec.dpll remains NULL. When ice_dpll_init_pins calls
ice_dpll_init_direct_pins(pf, true, outputs, count, num_outputs,
output_ops, eec.dpll, pps.dpll), if this second call (for output pins)
fails, the error path calls ice_dpll_deinit_direct_pins(pf, true, ...,
pps.dpll, eec.dpll).
Looking at ice_dpll_deinit_direct_pins:
static void ice_dpll_deinit_direct_pins(struct ice_pf *pf, bool cgu,
struct ice_dpll_pin *pins, int count,
const struct dpll_pin_ops *ops,
struct dpll_device *first,
struct dpll_device *second)
{
if (cgu) {
ice_dpll_unregister_pins(first, pins, ops, count);
ice_dpll_unregister_pins(second, pins, ops, count);
}
ice_dpll_release_pins(pins, count);
}
When cgu=true and second=NULL, ice_dpll_unregister_pins is called with
dpll=NULL. Then dpll_pin_unregister(dpll, pin) dereferences dpll with
xa_empty(&dpll->pin_refs), causing a NULL pointer dereference.
Shouldn't ice_dpll_deinit_direct_pins add NULL checks for first and second,
matching the guards you added in ice_dpll_init_direct_pins?
> diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.h b/drivers/net/ethernet/intel/ice/ice_dpll.h
> index ae42cdea0ee1..2c98b6c6deb0 100644
> --- a/drivers/net/ethernet/intel/ice/ice_dpll.h
> +++ b/drivers/net/ethernet/intel/ice/ice_dpll.h
[ ... ]
> @@ -173,3 +181,5 @@ static inline void ice_dpll_deinit(struct ice_pf *pf) { }
> #define ICE_CGU_R11_SYNCE_S_BYP_CLK GENMASK(6, 1)
>
> #define ICE_CGU_BYPASS_MUX_OFFSET_E825C 3
> +#define ICE_DPLL_UNMANAGED_PIN_NUM 4
> +#define ICE_DPLL_IN_ESYNC_ENABLED ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN
This isn't a bug, but ICE_DPLL_UNMANAGED_PIN_NUM is defined but never
used. Looking at the unmanaged pin descriptors, ice_e830_unmanaged_inputs
has 1 entry and ice_e830_unmanaged_outputs has 2 entries (totaling 3 pins,
not 4).
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [net-next,13/15] ice: add support for unmanaged DPLL on E830 NIC
2026-04-02 10:26 ` [net-next,13/15] " Paolo Abeni
@ 2026-04-03 15:44 ` Tony Nguyen
0 siblings, 0 replies; 22+ messages in thread
From: Tony Nguyen @ 2026-04-03 15:44 UTC (permalink / raw)
To: Paolo Abeni
Cc: andriy.shevchenko, pmenzel, aleksandr.loktionov, mika.westerberg,
mbloch, saeedm, piotr.kwapulinski, sx.rinitha, kuba,
grzegorz.nitka, netdev, przemyslaw.kitszel, arkadiusz.kubalewski,
tariqt, davem, dima.ruinskiy, bhelgaas, andrew+netdev, lukas,
jacob.e.keller, richardcochran, takkozu, enjuk,
maximilianpezzullo, joe, przemyslaw.korba, leon, vgrinber,
linux-pci, sunithax.d.mekala, corbet, vinicius.gomes,
ilpo.jarvinen, edumazet, linux-doc, kohei.enju, kohei, horms,
avigailx.dahan
On 4/2/2026 3:26 AM, Paolo Abeni wrote:
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
>
> For local reproduction steps see https://netdev-ai.bots.linux.dev/ai-local.html
> ---
> ice: add support for unmanaged DPLL on E830 NIC
>
> Hardware variants of E830 may support an unmanaged DPLL where the
> configuration is hardcoded within the hardware and firmware, meaning
> users cannot modify settings. However, users are able to check the DPLL
> lock status and obtain configuration information through the Linux DPLL
> and devlink health subsystem.
>
>> diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c
>> index 62f75701d652..2a9eb233dbf4 100644
>> --- a/drivers/net/ethernet/intel/ice/ice_dpll.c
>> +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c
>
> [ ... ]
>
>> @@ -3148,12 +3176,15 @@ ice_dpll_init_direct_pins(struct ice_pf *pf, bool cgu,
>> int ret;
>>
>> ret = ice_dpll_get_pins(pf, pins, start_idx, count, pf->dplls.clock_id);
>> - if (ret)
>> + if (!cgu || ret)
>> return ret;
>> - if (cgu) {
>> +
>> + if (first) {
>> ret = ice_dpll_register_pins(first, pins, ops, count);
>> if (ret)
>> goto release_pins;
>> + }
>> + if (second) {
>> ret = ice_dpll_register_pins(second, pins, ops, count);
>> if (ret)
>> goto unregister_first;
>> @@ -3162,7 +3193,8 @@ ice_dpll_init_direct_pins(struct ice_pf *pf, bool cgu,
>> return 0;
>>
>> unregister_first:
>> - ice_dpll_unregister_pins(first, pins, ops, count);
>> + if (first)
>> + ice_dpll_unregister_pins(first, pins, ops, count);
>> release_pins:
>> ice_dpll_release_pins(pins, count);
>> return ret;
>
> NULL checks were added to ice_dpll_init_direct_pins for handling unmanaged
> DPLL initialization where only one DPLL device is active. However, is the
> corresponding cleanup function ice_dpll_deinit_direct_pins missing the same
> NULL checks?
>
> In unmanaged mode, only pf->dplls.pps.dpll is initialized while
> pf->dplls.eec.dpll remains NULL. When ice_dpll_init_pins calls
> ice_dpll_init_direct_pins(pf, true, outputs, count, num_outputs,
> output_ops, eec.dpll, pps.dpll), if this second call (for output pins)
> fails, the error path calls ice_dpll_deinit_direct_pins(pf, true, ...,
> pps.dpll, eec.dpll).
>
> Looking at ice_dpll_deinit_direct_pins:
>
> static void ice_dpll_deinit_direct_pins(struct ice_pf *pf, bool cgu,
> struct ice_dpll_pin *pins, int count,
> const struct dpll_pin_ops *ops,
> struct dpll_device *first,
> struct dpll_device *second)
> {
> if (cgu) {
> ice_dpll_unregister_pins(first, pins, ops, count);
> ice_dpll_unregister_pins(second, pins, ops, count);
> }
> ice_dpll_release_pins(pins, count);
> }
>
> When cgu=true and second=NULL, ice_dpll_unregister_pins is called with
> dpll=NULL. Then dpll_pin_unregister(dpll, pin) dereferences dpll with
> xa_empty(&dpll->pin_refs), causing a NULL pointer dereference.
>
> Shouldn't ice_dpll_deinit_direct_pins add NULL checks for first and second,
> matching the guards you added in ice_dpll_init_direct_pins?
>
>> diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.h b/drivers/net/ethernet/intel/ice/ice_dpll.h
>> index ae42cdea0ee1..2c98b6c6deb0 100644
>> --- a/drivers/net/ethernet/intel/ice/ice_dpll.h
>> +++ b/drivers/net/ethernet/intel/ice/ice_dpll.h
>
> [ ... ]
>
>> @@ -173,3 +181,5 @@ static inline void ice_dpll_deinit(struct ice_pf *pf) { }
>> #define ICE_CGU_R11_SYNCE_S_BYP_CLK GENMASK(6, 1)
>>
>> #define ICE_CGU_BYPASS_MUX_OFFSET_E825C 3
>> +#define ICE_DPLL_UNMANAGED_PIN_NUM 4
>> +#define ICE_DPLL_IN_ESYNC_ENABLED ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN
>
> This isn't a bug, but ICE_DPLL_UNMANAGED_PIN_NUM is defined but never
> used. Looking at the unmanaged pin descriptors, ice_e830_unmanaged_inputs
> has 1 entry and ice_e830_unmanaged_outputs has 2 entries (totaling 3 pins,
> not 4).
Hi Paolo,
We're working on changes to resolve these issues.
Thanks,
Tony
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH net-next 14/15] ice: mention fw_activate action along with devlink reload
2026-03-30 23:02 [PATCH net-next 00/15][pull request] Intel Wired LAN Driver Updates 2026-03-30 (igc, igb, ice) Tony Nguyen
` (12 preceding siblings ...)
2026-03-30 23:02 ` [PATCH net-next 13/15] ice: add support for unmanaged DPLL on E830 NIC Tony Nguyen
@ 2026-03-30 23:02 ` Tony Nguyen
2026-03-30 23:02 ` [PATCH net-next 15/15] ice: dpll: Fix compilation warning Tony Nguyen
14 siblings, 0 replies; 22+ messages in thread
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Jacob Keller, anthony.l.nguyen, Aleksandr Loktionov,
Przemek Kitszel, Simon Horman
From: Jacob Keller <jacob.e.keller@intel.com>
The ice driver reports a helpful status message when updating firmware
indicating what action is necessary to enable the new firmware. This is
done because some updates require power cycling or rebooting the machine
but some can be activated via devlink.
The ice driver only supports activating firmware with the specific action
of "fw_activate" a bare "devlink dev reload" will *not* update the
firmware, and will only perform driver reinitialization.
Update the status message to explicitly reflect that the reload must use
the fw_activate action.
I considered modifying the text to spell out the full command, but felt
that was both overkill and something that would belong better as part of
the user space program and not hard coded into the kernel driver output.
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/ice/ice_fw_update.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_fw_update.c b/drivers/net/ethernet/intel/ice/ice_fw_update.c
index c143e546dd8c..36314610927b 100644
--- a/drivers/net/ethernet/intel/ice/ice_fw_update.c
+++ b/drivers/net/ethernet/intel/ice/ice_fw_update.c
@@ -726,7 +726,7 @@ static int ice_finalize_update(struct pldmfw *context)
switch (priv->reset_level) {
case ICE_AQC_NVM_EMPR_FLAG:
devlink_flash_update_status_notify(devlink,
- "Activate new firmware by devlink reload",
+ "Activate new firmware by devlink reload action fw_activate",
NULL, 0, 0);
break;
case ICE_AQC_NVM_PERST_FLAG:
--
2.47.1
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH net-next 15/15] ice: dpll: Fix compilation warning
2026-03-30 23:02 [PATCH net-next 00/15][pull request] Intel Wired LAN Driver Updates 2026-03-30 (igc, igb, ice) Tony Nguyen
` (13 preceding siblings ...)
2026-03-30 23:02 ` [PATCH net-next 14/15] ice: mention fw_activate action along with devlink reload Tony Nguyen
@ 2026-03-30 23:02 ` Tony Nguyen
14 siblings, 0 replies; 22+ messages in thread
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Przemyslaw Korba, anthony.l.nguyen, Przemek Kitszel,
Aleksandr Loktionov
From: Przemyslaw Korba <przemyslaw.korba@intel.com>
Introduced by commit ad1df4f2d591 ("ice: dpll: Support E825-C SyncE and
dynamic pin discovery"):
ice_dpll.c: In function 'ice_dpll_init':
ice_dpll.c:3588:59: error: '%u' directive output may be truncated
writing between 1 and 10 bytes into a region of size 4
[-Werror=format-truncation=] snprintf(pin_name, sizeof(pin_name),
"rclk%u", i);
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Signed-off-by: Przemyslaw Korba <przemyslaw.korba@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/ice/ice_dpll.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c
index 2a9eb233dbf4..deb05976d687 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.c
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.c
@@ -3571,7 +3571,7 @@ static int
ice_dpll_init_fwnode_pins(struct ice_pf *pf, struct ice_dpll_pin *pins,
int start_idx)
{
- char pin_name[8];
+ char pin_name[16];
int i, ret;
pf->dplls.wq = create_singlethread_workqueue("ice_dpll_wq");
--
2.47.1
^ permalink raw reply related [flat|nested] 22+ messages in thread