* [Intel-wired-lan] [PATCH iwl-next v2] ixgbe: Implement PCI reset handler
@ 2026-06-18 14:22 ` Sergey Temerkhanov
0 siblings, 0 replies; 3+ messages in thread
From: Sergey Temerkhanov @ 2026-06-18 14:22 UTC (permalink / raw)
To: intel-wired-lan; +Cc: netdev, pmenzel
Implement PCI device reset handler to allow the network device to
get re-initialized and function after a PCI-level reset.
This is necessary for the adapter to avoid TX queue timeouts
occurring when the PCI reset is initiated via sysfs during
the operation
Signed-off-by: Sergey Temerkhanov <sergey.temerkhanov@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
Previous version: https://lore.kernel.org/netdev/MW4PR11MB6864BC9CA84F060AF7E0248480E42@MW4PR11MB6864.namprd11.prod.outlook.com/
v1->v2 changes: Rearranged the order of operations, switched to poll_timeout_us() macro
drivers/net/ethernet/intel/ixgbe/ixgbe.h | 1 +
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 82 +++++++++++++++++++
2 files changed, 83 insertions(+)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 594ccb28da20..c4b0c5bb89c6 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -912,6 +912,7 @@ enum ixgbe_state_t {
__IXGBE_PTP_TX_IN_PROGRESS,
__IXGBE_RESET_REQUESTED,
__IXGBE_PHY_INIT_COMPLETE,
+ __IXGBE_PCIE_RESET_IN_PROGRESS,
};
struct ixgbe_cb {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 2ac274c73d61..0fb64aef223e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -12352,6 +12352,86 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
return result;
}
+/* 1500 us poll interval */
+#define IXGBE_RESET_PREP_POLL_INTERVAL_US 1500
+/* 2 second timeout to acquire reset lock before proceeding */
+#define IXGBE_RESET_PREP_TIMEOUT_US 2000000
+
+/**
+ * ixgbe_reset_prep - called before the pci bus is reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Prepare the card for a reset, preventing the service task from running.
+ */
+static void ixgbe_reset_prep(struct pci_dev *pdev)
+{
+ struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
+
+ if (!adapter)
+ return;
+
+ if (poll_timeout_us(test_and_set_bit(__IXGBE_RESETTING, &adapter->state),
+ test_bit(__IXGBE_RESETTING, &adapter->state),
+ IXGBE_RESET_PREP_POLL_INTERVAL_US,
+ IXGBE_RESET_PREP_TIMEOUT_US, false)) {
+ /* ixgbe_reset_done() will exit early if this happens.
+ * A retry will be needed
+ */
+ e_err(drv, "Timed out waiting for __IXGBE_RESETTING to be released. Reset is needed\n");
+ return;
+ }
+
+ /* Sync __IXGBE_RESETTING */
+ smp_mb__after_atomic();
+
+ if (test_bit(__IXGBE_SERVICE_INITED, &adapter->state)) {
+ /* Prevent the service task from being requeued in the timer callback */
+ timer_delete_sync(&adapter->service_timer);
+ /* Cancel any possibly queued service task */
+ cancel_work_sync(&adapter->service_task);
+ }
+
+ pci_clear_master(pdev);
+
+ set_bit(__IXGBE_PCIE_RESET_IN_PROGRESS, &adapter->state);
+}
+
+/**
+ * ixgbe_reset_done - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Allow the service task to run and schedule re-initialization.
+ */
+static void ixgbe_reset_done(struct pci_dev *pdev)
+{
+ struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
+
+ if (!adapter)
+ return;
+
+ if (!test_and_clear_bit(__IXGBE_PCIE_RESET_IN_PROGRESS, &adapter->state)) {
+ /* Should never get here */
+ e_err(drv, "Reset done called without PCIe reset in progress\n");
+ return;
+ }
+
+ pci_set_master(pdev);
+
+ /* Allow the service task to run */
+ if (!test_bit(__IXGBE_REMOVING, &adapter->state)) {
+ clear_bit(__IXGBE_RESETTING, &adapter->state);
+ /* Sync __IXGBE_RESETTING */
+ smp_mb__after_atomic();
+ }
+
+ /* Schedule re-initialization */
+ if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+ set_bit(__IXGBE_RESET_REQUESTED, &adapter->state);
+ if (test_bit(__IXGBE_SERVICE_INITED, &adapter->state))
+ mod_timer(&adapter->service_timer, jiffies + 1);
+ }
+}
+
/**
* ixgbe_io_resume - called when traffic can start flowing again.
* @pdev: Pointer to PCI device
@@ -12384,6 +12464,8 @@ static const struct pci_error_handlers ixgbe_err_handler = {
.error_detected = ixgbe_io_error_detected,
.slot_reset = ixgbe_io_slot_reset,
.resume = ixgbe_io_resume,
+ .reset_prepare = ixgbe_reset_prep,
+ .reset_done = ixgbe_reset_done,
};
static DEFINE_SIMPLE_DEV_PM_OPS(ixgbe_pm_ops, ixgbe_suspend, ixgbe_resume);
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH iwl-next v2] ixgbe: Implement PCI reset handler
@ 2026-06-18 14:22 ` Sergey Temerkhanov
0 siblings, 0 replies; 3+ messages in thread
From: Sergey Temerkhanov @ 2026-06-18 14:22 UTC (permalink / raw)
To: intel-wired-lan; +Cc: netdev, pmenzel
Implement PCI device reset handler to allow the network device to
get re-initialized and function after a PCI-level reset.
This is necessary for the adapter to avoid TX queue timeouts
occurring when the PCI reset is initiated via sysfs during
the operation
Signed-off-by: Sergey Temerkhanov <sergey.temerkhanov@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
Previous version: https://lore.kernel.org/netdev/MW4PR11MB6864BC9CA84F060AF7E0248480E42@MW4PR11MB6864.namprd11.prod.outlook.com/
v1->v2 changes: Rearranged the order of operations, switched to poll_timeout_us() macro
drivers/net/ethernet/intel/ixgbe/ixgbe.h | 1 +
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 82 +++++++++++++++++++
2 files changed, 83 insertions(+)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 594ccb28da20..c4b0c5bb89c6 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -912,6 +912,7 @@ enum ixgbe_state_t {
__IXGBE_PTP_TX_IN_PROGRESS,
__IXGBE_RESET_REQUESTED,
__IXGBE_PHY_INIT_COMPLETE,
+ __IXGBE_PCIE_RESET_IN_PROGRESS,
};
struct ixgbe_cb {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 2ac274c73d61..0fb64aef223e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -12352,6 +12352,86 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
return result;
}
+/* 1500 us poll interval */
+#define IXGBE_RESET_PREP_POLL_INTERVAL_US 1500
+/* 2 second timeout to acquire reset lock before proceeding */
+#define IXGBE_RESET_PREP_TIMEOUT_US 2000000
+
+/**
+ * ixgbe_reset_prep - called before the pci bus is reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Prepare the card for a reset, preventing the service task from running.
+ */
+static void ixgbe_reset_prep(struct pci_dev *pdev)
+{
+ struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
+
+ if (!adapter)
+ return;
+
+ if (poll_timeout_us(test_and_set_bit(__IXGBE_RESETTING, &adapter->state),
+ test_bit(__IXGBE_RESETTING, &adapter->state),
+ IXGBE_RESET_PREP_POLL_INTERVAL_US,
+ IXGBE_RESET_PREP_TIMEOUT_US, false)) {
+ /* ixgbe_reset_done() will exit early if this happens.
+ * A retry will be needed
+ */
+ e_err(drv, "Timed out waiting for __IXGBE_RESETTING to be released. Reset is needed\n");
+ return;
+ }
+
+ /* Sync __IXGBE_RESETTING */
+ smp_mb__after_atomic();
+
+ if (test_bit(__IXGBE_SERVICE_INITED, &adapter->state)) {
+ /* Prevent the service task from being requeued in the timer callback */
+ timer_delete_sync(&adapter->service_timer);
+ /* Cancel any possibly queued service task */
+ cancel_work_sync(&adapter->service_task);
+ }
+
+ pci_clear_master(pdev);
+
+ set_bit(__IXGBE_PCIE_RESET_IN_PROGRESS, &adapter->state);
+}
+
+/**
+ * ixgbe_reset_done - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Allow the service task to run and schedule re-initialization.
+ */
+static void ixgbe_reset_done(struct pci_dev *pdev)
+{
+ struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
+
+ if (!adapter)
+ return;
+
+ if (!test_and_clear_bit(__IXGBE_PCIE_RESET_IN_PROGRESS, &adapter->state)) {
+ /* Should never get here */
+ e_err(drv, "Reset done called without PCIe reset in progress\n");
+ return;
+ }
+
+ pci_set_master(pdev);
+
+ /* Allow the service task to run */
+ if (!test_bit(__IXGBE_REMOVING, &adapter->state)) {
+ clear_bit(__IXGBE_RESETTING, &adapter->state);
+ /* Sync __IXGBE_RESETTING */
+ smp_mb__after_atomic();
+ }
+
+ /* Schedule re-initialization */
+ if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+ set_bit(__IXGBE_RESET_REQUESTED, &adapter->state);
+ if (test_bit(__IXGBE_SERVICE_INITED, &adapter->state))
+ mod_timer(&adapter->service_timer, jiffies + 1);
+ }
+}
+
/**
* ixgbe_io_resume - called when traffic can start flowing again.
* @pdev: Pointer to PCI device
@@ -12384,6 +12464,8 @@ static const struct pci_error_handlers ixgbe_err_handler = {
.error_detected = ixgbe_io_error_detected,
.slot_reset = ixgbe_io_slot_reset,
.resume = ixgbe_io_resume,
+ .reset_prepare = ixgbe_reset_prep,
+ .reset_done = ixgbe_reset_done,
};
static DEFINE_SIMPLE_DEV_PM_OPS(ixgbe_pm_ops, ixgbe_suspend, ixgbe_resume);
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [Intel-wired-lan] [PATCH iwl-next v2] ixgbe: Implement PCI reset handler
2026-06-18 14:22 ` Sergey Temerkhanov
(?)
@ 2026-06-20 8:53 ` Simon Horman
-1 siblings, 0 replies; 3+ messages in thread
From: Simon Horman @ 2026-06-20 8:53 UTC (permalink / raw)
To: sergey.temerkhanov; +Cc: Simon Horman, intel-wired-lan, netdev, pmenzel
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://sashiko.dev
---
ixgbe: Implement PCI reset handler
Implement PCI device reset handler to allow the network device to
get re-initialized and function after a PCI-level reset.
> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
[ ... ]
> @@ -12338,6 +12338,86 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
> +static void ixgbe_reset_prep(struct pci_dev *pdev)
> +{
> + struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
> +
> + if (!adapter)
> + return;
> +
> + if (poll_timeout_us(test_and_set_bit(__IXGBE_RESETTING, &adapter->state),
> + test_bit(__IXGBE_RESETTING, &adapter->state),
[Severity: Medium]
Does this introduce a new instance of an ad-hoc bit lock?
According to the networking drivers guidelines, using bit operations like
test_and_set_bit() to guard critical sections instead of proper
synchronization primitives like a mutex or spinlock can hide issues from
lockdep and lacks deadlock detection.
[Severity: Critical]
Does this misuse the poll_timeout_us() macro?
The macro executes the operation before evaluating the condition. Since
test_and_set_bit() unconditionally sets the bit to 1, test_bit() will always
evaluate to true on the very first loop iteration, regardless of whether the
lock was already held.
Doesn't this completely break mutual exclusion?
> + IXGBE_RESET_PREP_POLL_INTERVAL_US,
> + IXGBE_RESET_PREP_TIMEOUT_US, false)) {
> + /* ixgbe_reset_done() will exit early if this happens.
> + * A retry will be needed
> + */
> + e_err(drv, "Timed out waiting for __IXGBE_RESETTING to be released. Reset is needed\n");
> + return;
[Severity: High]
If this times out and returns early, won't it abandon the software
reinitialization process while the PCI subsystem proceeds with the physical
reset?
The .reset_prepare callback returns void, so the reset continues. By
returning early without setting __IXGBE_PCIE_RESET_IN_PROGRESS, critical
teardowns are skipped, and ixgbe_reset_done() will also bail out early:
ixgbe_reset_done() {
if (!test_and_clear_bit(__IXGBE_PCIE_RESET_IN_PROGRESS, &adapter->state)) {
e_err(drv, "Reset done called without PCIe reset in progress\n");
return;
}
}
Could this permanently break the network interface until the module is
reloaded?
> + }
> +
> + /* Sync __IXGBE_RESETTING */
> + smp_mb__after_atomic();
> +
> + if (test_bit(__IXGBE_SERVICE_INITED, &adapter->state)) {
> + /* Prevent the service task from being requeued in the timer callback */
> + timer_delete_sync(&adapter->service_timer);
> + /* Cancel any possibly queued service task */
> + cancel_work_sync(&adapter->service_task);
[Severity: Critical]
Can this sequence cause a deadlock with the service task?
Here in ixgbe_reset_prep(), __IXGBE_RESETTING has just been acquired,
and then cancel_work_sync(&adapter->service_task) blocks waiting for
the service task to complete.
However, if the active service task reaches ixgbe_reinit_locked():
ixgbe_reinit_locked() {
while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
usleep_range(1000, 2000);
...
}
The service task will spin infinitely waiting for __IXGBE_RESETTING to be
cleared. Since ixgbe_reset_prep() holds the bit lock and is blocked waiting
for the service task, neither thread can make progress.
> + }
> +
> + pci_clear_master(pdev);
> +
> + set_bit(__IXGBE_PCIE_RESET_IN_PROGRESS, &adapter->state);
> +}
[ ... ]
> +static void ixgbe_reset_done(struct pci_dev *pdev)
> +{
> + struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
[ ... ]
> + /* Allow the service task to run */
> + if (!test_bit(__IXGBE_REMOVING, &adapter->state)) {
> + clear_bit(__IXGBE_RESETTING, &adapter->state);
> + /* Sync __IXGBE_RESETTING */
> + smp_mb__after_atomic();
[Severity: Medium]
Does this provide the correct release semantics for the ad-hoc lock?
The clear_bit() operation does not imply a memory barrier, and
smp_mb__after_atomic() only orders memory operations that occur after the
atomic operation.
Could memory accesses from within the critical section (like the
pci_set_master() call earlier) bleed past the lock release, allowing other
threads to acquire the lock too early?
Is it possible to use clear_bit_unlock() or place an smp_mb__before_atomic()
prior to the clear_bit() instead?
> + }
[ ... ]
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-06-20 8:53 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-18 14:22 [Intel-wired-lan] [PATCH iwl-next v2] ixgbe: Implement PCI reset handler Sergey Temerkhanov
2026-06-18 14:22 ` Sergey Temerkhanov
2026-06-20 8:53 ` [Intel-wired-lan] " Simon Horman
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.