Skip to content

Commit

Permalink
igc: Add lock to safeguard global Qbv variables
Browse files Browse the repository at this point in the history
commit 06b4125 upstream.

Access to shared variables through hrtimer requires locking in order
to protect the variables because actions to write into these variables
(oper_gate_closed, admin_gate_closed, and qbv_transition) might potentially
occur simultaneously. This patch provides a locking mechanisms to avoid
such scenarios.

Fixes: 175c241 ("igc: Fix TX Hang issue when QBV Gate is closed")
Suggested-by: Leon Romanovsky <leon@kernel.org>
Signed-off-by: Muhammad Husaini Zulkifli <muhammad.husaini.zulkifli@intel.com>
Tested-by: Naama Meir <naamax.meir@linux.intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Link: https://lore.kernel.org/r/20230807205129.3129346-1-anthony.l.nguyen@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
zulkifl3 authored and gregkh committed Aug 16, 2023
1 parent c951a1e commit d753b5f
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 2 deletions.
4 changes: 4 additions & 0 deletions drivers/net/ethernet/intel/igc/igc.h
Expand Up @@ -195,6 +195,10 @@ struct igc_adapter {
u32 qbv_config_change_errors;
bool qbv_transition;
unsigned int qbv_count;
/* Access to oper_gate_closed, admin_gate_closed and qbv_transition
* are protected by the qbv_tx_lock.
*/
spinlock_t qbv_tx_lock;

/* OS defined structs */
struct pci_dev *pdev;
Expand Down
34 changes: 32 additions & 2 deletions drivers/net/ethernet/intel/igc/igc_main.c
Expand Up @@ -4799,6 +4799,7 @@ static int igc_sw_init(struct igc_adapter *adapter)
adapter->nfc_rule_count = 0;

spin_lock_init(&adapter->stats64_lock);
spin_lock_init(&adapter->qbv_tx_lock);
/* Assume MSI-X interrupts, will be checked during IRQ allocation */
adapter->flags |= IGC_FLAG_HAS_MSIX;

Expand Down Expand Up @@ -6117,15 +6118,15 @@ static int igc_tsn_enable_launchtime(struct igc_adapter *adapter,
return igc_tsn_offload_apply(adapter);
}

static int igc_tsn_clear_schedule(struct igc_adapter *adapter)
static int igc_qbv_clear_schedule(struct igc_adapter *adapter)
{
unsigned long flags;
int i;

adapter->base_time = 0;
adapter->cycle_time = NSEC_PER_SEC;
adapter->taprio_offload_enable = false;
adapter->qbv_config_change_errors = 0;
adapter->qbv_transition = false;
adapter->qbv_count = 0;

for (i = 0; i < adapter->num_tx_queues; i++) {
Expand All @@ -6134,10 +6135,28 @@ static int igc_tsn_clear_schedule(struct igc_adapter *adapter)
ring->start_time = 0;
ring->end_time = NSEC_PER_SEC;
ring->max_sdu = 0;
}

spin_lock_irqsave(&adapter->qbv_tx_lock, flags);

adapter->qbv_transition = false;

for (i = 0; i < adapter->num_tx_queues; i++) {
struct igc_ring *ring = adapter->tx_ring[i];

ring->oper_gate_closed = false;
ring->admin_gate_closed = false;
}

spin_unlock_irqrestore(&adapter->qbv_tx_lock, flags);

return 0;
}

static int igc_tsn_clear_schedule(struct igc_adapter *adapter)
{
igc_qbv_clear_schedule(adapter);

return 0;
}

Expand All @@ -6148,6 +6167,7 @@ static int igc_save_qbv_schedule(struct igc_adapter *adapter,
struct igc_hw *hw = &adapter->hw;
u32 start_time = 0, end_time = 0;
struct timespec64 now;
unsigned long flags;
size_t n;
int i;

Expand Down Expand Up @@ -6215,6 +6235,8 @@ static int igc_save_qbv_schedule(struct igc_adapter *adapter,
start_time += e->interval;
}

spin_lock_irqsave(&adapter->qbv_tx_lock, flags);

/* Check whether a queue gets configured.
* If not, set the start and end time to be end time.
*/
Expand All @@ -6239,6 +6261,8 @@ static int igc_save_qbv_schedule(struct igc_adapter *adapter,
}
}

spin_unlock_irqrestore(&adapter->qbv_tx_lock, flags);

for (i = 0; i < adapter->num_tx_queues; i++) {
struct igc_ring *ring = adapter->tx_ring[i];
struct net_device *dev = adapter->netdev;
Expand Down Expand Up @@ -6603,8 +6627,11 @@ static enum hrtimer_restart igc_qbv_scheduling_timer(struct hrtimer *timer)
{
struct igc_adapter *adapter = container_of(timer, struct igc_adapter,
hrtimer);
unsigned long flags;
unsigned int i;

spin_lock_irqsave(&adapter->qbv_tx_lock, flags);

adapter->qbv_transition = true;
for (i = 0; i < adapter->num_tx_queues; i++) {
struct igc_ring *tx_ring = adapter->tx_ring[i];
Expand All @@ -6617,6 +6644,9 @@ static enum hrtimer_restart igc_qbv_scheduling_timer(struct hrtimer *timer)
}
}
adapter->qbv_transition = false;

spin_unlock_irqrestore(&adapter->qbv_tx_lock, flags);

return HRTIMER_NORESTART;
}

Expand Down

0 comments on commit d753b5f

Please sign in to comment.