| From 913867b61bb7d30a5325fe0618f495bb3ef294d3 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 20 Feb 2024 15:57:11 -0800 |
| Subject: igb: Fix missing time sync events |
| |
| From: Vinicius Costa Gomes <vinicius.gomes@intel.com> |
| |
| [ Upstream commit ee14cc9ea19ba9678177e2224a9c58cce5937c73 ] |
| |
| Fix "double" clearing of interrupts, which can cause external events |
| or timestamps to be missed. |
| |
| The E1000_TSIRC Time Sync Interrupt Cause register can be cleared in two |
| ways, by either reading it or by writing '1' into the specific cause |
| bit. This is documented in section 8.16.1. |
| |
| The following flow was used: |
| 1. read E1000_TSIRC into 'tsicr'; |
| 2. handle the interrupts present into 'tsirc' and mark them in 'ack'; |
| 3. write 'ack' into E1000_TSICR; |
| |
| As both (1) and (3) will clear the interrupt cause, if the same |
| interrupt happens again between (1) and (3) it will be ignored, |
| causing events to be missed. |
| |
| Remove the extra clear in (3). |
| |
| Fixes: 00c65578b47b ("igb: enable internal PPS for the i210") |
| Acked-by: Richard Cochran <richardcochran@gmail.com> |
| Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com> |
| Tested-by: Pucha Himasekhar Reddy <himasekharx.reddy.pucha@intel.com> (A Contingent worker at Intel) |
| Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/net/ethernet/intel/igb/igb_main.c | 23 +++++------------------ |
| 1 file changed, 5 insertions(+), 18 deletions(-) |
| |
| diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c |
| index c0e2323e50c6e..5d8d5915bc276 100644 |
| --- a/drivers/net/ethernet/intel/igb/igb_main.c |
| +++ b/drivers/net/ethernet/intel/igb/igb_main.c |
| @@ -6555,44 +6555,31 @@ static void igb_extts(struct igb_adapter *adapter, int tsintr_tt) |
| static void igb_tsync_interrupt(struct igb_adapter *adapter) |
| { |
| struct e1000_hw *hw = &adapter->hw; |
| - u32 ack = 0, tsicr = rd32(E1000_TSICR); |
| + u32 tsicr = rd32(E1000_TSICR); |
| struct ptp_clock_event event; |
| |
| if (tsicr & TSINTR_SYS_WRAP) { |
| event.type = PTP_CLOCK_PPS; |
| if (adapter->ptp_caps.pps) |
| ptp_clock_event(adapter->ptp_clock, &event); |
| - ack |= TSINTR_SYS_WRAP; |
| } |
| |
| if (tsicr & E1000_TSICR_TXTS) { |
| /* retrieve hardware timestamp */ |
| schedule_work(&adapter->ptp_tx_work); |
| - ack |= E1000_TSICR_TXTS; |
| } |
| |
| - if (tsicr & TSINTR_TT0) { |
| + if (tsicr & TSINTR_TT0) |
| igb_perout(adapter, 0); |
| - ack |= TSINTR_TT0; |
| - } |
| |
| - if (tsicr & TSINTR_TT1) { |
| + if (tsicr & TSINTR_TT1) |
| igb_perout(adapter, 1); |
| - ack |= TSINTR_TT1; |
| - } |
| |
| - if (tsicr & TSINTR_AUTT0) { |
| + if (tsicr & TSINTR_AUTT0) |
| igb_extts(adapter, 0); |
| - ack |= TSINTR_AUTT0; |
| - } |
| |
| - if (tsicr & TSINTR_AUTT1) { |
| + if (tsicr & TSINTR_AUTT1) |
| igb_extts(adapter, 1); |
| - ack |= TSINTR_AUTT1; |
| - } |
| - |
| - /* acknowledge the interrupts */ |
| - wr32(E1000_TSICR, ack); |
| } |
| |
| static irqreturn_t igb_msix_other(int irq, void *data) |
| -- |
| 2.43.0 |
| |