Skip to content

Commit 06b4125

Browse files
zulkifl3kuba-moo
authored andcommitted
igc: Add lock to safeguard global Qbv variables
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>
1 parent b9077ef commit 06b4125

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

drivers/net/ethernet/intel/igc/igc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ struct igc_adapter {
195195
u32 qbv_config_change_errors;
196196
bool qbv_transition;
197197
unsigned int qbv_count;
198+
/* Access to oper_gate_closed, admin_gate_closed and qbv_transition
199+
* are protected by the qbv_tx_lock.
200+
*/
201+
spinlock_t qbv_tx_lock;
198202

199203
/* OS defined structs */
200204
struct pci_dev *pdev;

drivers/net/ethernet/intel/igc/igc_main.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4801,6 +4801,7 @@ static int igc_sw_init(struct igc_adapter *adapter)
48014801
adapter->nfc_rule_count = 0;
48024802

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

@@ -6119,15 +6120,15 @@ static int igc_tsn_enable_launchtime(struct igc_adapter *adapter,
61196120
return igc_tsn_offload_apply(adapter);
61206121
}
61216122

6122-
static int igc_tsn_clear_schedule(struct igc_adapter *adapter)
6123+
static int igc_qbv_clear_schedule(struct igc_adapter *adapter)
61236124
{
6125+
unsigned long flags;
61246126
int i;
61256127

61266128
adapter->base_time = 0;
61276129
adapter->cycle_time = NSEC_PER_SEC;
61286130
adapter->taprio_offload_enable = false;
61296131
adapter->qbv_config_change_errors = 0;
6130-
adapter->qbv_transition = false;
61316132
adapter->qbv_count = 0;
61326133

61336134
for (i = 0; i < adapter->num_tx_queues; i++) {
@@ -6136,10 +6137,28 @@ static int igc_tsn_clear_schedule(struct igc_adapter *adapter)
61366137
ring->start_time = 0;
61376138
ring->end_time = NSEC_PER_SEC;
61386139
ring->max_sdu = 0;
6140+
}
6141+
6142+
spin_lock_irqsave(&adapter->qbv_tx_lock, flags);
6143+
6144+
adapter->qbv_transition = false;
6145+
6146+
for (i = 0; i < adapter->num_tx_queues; i++) {
6147+
struct igc_ring *ring = adapter->tx_ring[i];
6148+
61396149
ring->oper_gate_closed = false;
61406150
ring->admin_gate_closed = false;
61416151
}
61426152

6153+
spin_unlock_irqrestore(&adapter->qbv_tx_lock, flags);
6154+
6155+
return 0;
6156+
}
6157+
6158+
static int igc_tsn_clear_schedule(struct igc_adapter *adapter)
6159+
{
6160+
igc_qbv_clear_schedule(adapter);
6161+
61436162
return 0;
61446163
}
61456164

@@ -6150,6 +6169,7 @@ static int igc_save_qbv_schedule(struct igc_adapter *adapter,
61506169
struct igc_hw *hw = &adapter->hw;
61516170
u32 start_time = 0, end_time = 0;
61526171
struct timespec64 now;
6172+
unsigned long flags;
61536173
size_t n;
61546174
int i;
61556175

@@ -6217,6 +6237,8 @@ static int igc_save_qbv_schedule(struct igc_adapter *adapter,
62176237
start_time += e->interval;
62186238
}
62196239

6240+
spin_lock_irqsave(&adapter->qbv_tx_lock, flags);
6241+
62206242
/* Check whether a queue gets configured.
62216243
* If not, set the start and end time to be end time.
62226244
*/
@@ -6241,6 +6263,8 @@ static int igc_save_qbv_schedule(struct igc_adapter *adapter,
62416263
}
62426264
}
62436265

6266+
spin_unlock_irqrestore(&adapter->qbv_tx_lock, flags);
6267+
62446268
for (i = 0; i < adapter->num_tx_queues; i++) {
62456269
struct igc_ring *ring = adapter->tx_ring[i];
62466270
struct net_device *dev = adapter->netdev;
@@ -6619,8 +6643,11 @@ static enum hrtimer_restart igc_qbv_scheduling_timer(struct hrtimer *timer)
66196643
{
66206644
struct igc_adapter *adapter = container_of(timer, struct igc_adapter,
66216645
hrtimer);
6646+
unsigned long flags;
66226647
unsigned int i;
66236648

6649+
spin_lock_irqsave(&adapter->qbv_tx_lock, flags);
6650+
66246651
adapter->qbv_transition = true;
66256652
for (i = 0; i < adapter->num_tx_queues; i++) {
66266653
struct igc_ring *tx_ring = adapter->tx_ring[i];
@@ -6633,6 +6660,9 @@ static enum hrtimer_restart igc_qbv_scheduling_timer(struct hrtimer *timer)
66336660
}
66346661
}
66356662
adapter->qbv_transition = false;
6663+
6664+
spin_unlock_irqrestore(&adapter->qbv_tx_lock, flags);
6665+
66366666
return HRTIMER_NORESTART;
66376667
}
66386668

0 commit comments

Comments
 (0)