diff mbox series

[iwl-next,2/5] ice: schedule service task in IRQ thread_fn

Message ID 20230526222158.2685796-3-jacob.e.keller@intel.com
State Changes Requested
Headers show
Series ice: Improve miscellaneous interrupt code | expand

Commit Message

Jacob Keller May 26, 2023, 10:21 p.m. UTC
From: Karol Kolacinski <karol.kolacinski@intel.com>

If the kernel is configured with CONFIG_PREEMPT_RT, scheduling the service
task in interrupt context can result in a kernel panic. This is a result of
ice_service_task_schedule calling queue_work.

Move the ice_service_task_schedule() call into the miscellaneous IRQ thread
that functions as the interrupt bottom half.

Signed-off-by: Karol Kolacinski <karol.kolacinski@intel.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_main.c | 14 ++++----------
 1 file changed, 4 insertions(+), 10 deletions(-)

Comments

Michal Schmidt May 29, 2023, 10:42 a.m. UTC | #1
Den 27.05.2023 kl. 00.21 skrev Jacob Keller:
> From: Karol Kolacinski <karol.kolacinski@intel.com>
> 
> If the kernel is configured with CONFIG_PREEMPT_RT, scheduling the service
> task in interrupt context can result in a kernel panic. This is a result of
> ice_service_task_schedule calling queue_work.

Is it really the case on current kernels that one cannot use queue_work 
in that context?
The previous posting of this patch showed a stack trace from a 
3.10-based vendor kernel. Has the crash been seen on anything recent?
I think the workqueue code has been safe to use in atomic context on 
even on PREEMPT_RT since commit fe3bc8a988a4 ("Merge branch 'for-5.8' of 
git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq").

That said, the patch looks OK to me. It makes the code cleaner. I object 
only to the description.

Michal

> Move the ice_service_task_schedule() call into the miscellaneous IRQ thread
> that functions as the interrupt bottom half.
> 
> Signed-off-by: Karol Kolacinski <karol.kolacinski@intel.com>
> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
> ---
>   drivers/net/ethernet/intel/ice/ice_main.c | 14 ++++----------
>   1 file changed, 4 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
> index 9e4d7d884115..8b59632ec6b1 100644
> --- a/drivers/net/ethernet/intel/ice/ice_main.c
> +++ b/drivers/net/ethernet/intel/ice/ice_main.c
> @@ -3058,7 +3058,6 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
>   {
>   	struct ice_pf *pf = (struct ice_pf *)data;
>   	struct ice_hw *hw = &pf->hw;
> -	irqreturn_t ret = IRQ_NONE;
>   	struct device *dev;
>   	u32 oicr, ena_mask;
>   
> @@ -3139,10 +3138,8 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
>   
>   	if (oicr & PFINT_OICR_TSYN_TX_M) {
>   		ena_mask &= ~PFINT_OICR_TSYN_TX_M;
> -		if (!hw->reset_ongoing) {
> +		if (!hw->reset_ongoing)
>   			pf->oicr_misc |= PFINT_OICR_TSYN_TX_M;
> -			ret = IRQ_WAKE_THREAD;
> -		}
>   	}
>   
>   	if (oicr & PFINT_OICR_TSYN_EVNT_M) {
> @@ -3159,7 +3156,6 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
>   					       GLTSYN_STAT_EVENT2_M);
>   
>   			pf->oicr_misc |= PFINT_OICR_TSYN_EVNT_M;
> -			ret = IRQ_WAKE_THREAD;
>   		}
>   	}
>   
> @@ -3180,16 +3176,12 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
>   		if (oicr & (PFINT_OICR_PCI_EXCEPTION_M |
>   			    PFINT_OICR_ECC_ERR_M)) {
>   			set_bit(ICE_PFR_REQ, pf->state);
> -			ice_service_task_schedule(pf);
>   		}
>   	}
> -	if (!ret)
> -		ret = IRQ_HANDLED;
>   
> -	ice_service_task_schedule(pf);
>   	ice_irq_dynamic_ena(hw, NULL, NULL);
>   
> -	return ret;
> +	return IRQ_WAKE_THREAD;
>   }
>   
>   /**
> @@ -3204,6 +3196,8 @@ static irqreturn_t ice_misc_intr_thread_fn(int __always_unused irq, void *data)
>   	if (ice_is_reset_in_progress(pf->state))
>   		return IRQ_HANDLED;
>   
> +	ice_service_task_schedule(pf);
> +
>   	if (pf->oicr_misc & PFINT_OICR_TSYN_EVNT_M) {
>   		ice_ptp_extts_event(pf);
>   		pf->oicr_misc &= ~PFINT_OICR_TSYN_EVNT_M;
Jacob Keller May 30, 2023, 5:13 p.m. UTC | #2
> -----Original Message-----
> From: Michal Schmidt <mschmidt@redhat.com>
> Sent: Monday, May 29, 2023 3:43 AM
> To: Keller, Jacob E <jacob.e.keller@intel.com>; Intel Wired LAN <intel-wired-
> lan@lists.osuosl.org>; Nguyen, Anthony L <anthony.l.nguyen@intel.com>
> Cc: Kolacinski, Karol <karol.kolacinski@intel.com>
> Subject: Re: [Intel-wired-lan] [PATCH iwl-next 2/5] ice: schedule service task in
> IRQ thread_fn
> 
> Den 27.05.2023 kl. 00.21 skrev Jacob Keller:
> > From: Karol Kolacinski <karol.kolacinski@intel.com>
> >
> > If the kernel is configured with CONFIG_PREEMPT_RT, scheduling the service
> > task in interrupt context can result in a kernel panic. This is a result of
> > ice_service_task_schedule calling queue_work.
> 
> Is it really the case on current kernels that one cannot use queue_work
> in that context?
> The previous posting of this patch showed a stack trace from a
> 3.10-based vendor kernel. Has the crash been seen on anything recent?
> I think the workqueue code has been safe to use in atomic context on
> even on PREEMPT_RT since commit fe3bc8a988a4 ("Merge branch 'for-5.8' of
> git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq").
> 
> That said, the patch looks OK to me. It makes the code cleaner. I object
> only to the description.
> 
> Michal
> 

Hmm... we had developed this fix some time ago for a customer who was on an older stable kernel that didn't have this fix. I wasn't aware of it, so I assumed it was still a problem when writing this message for upstream. I think I prefer the overall code design here especially since we're moving processing of external timestamps.

I'll re-write the commit message.
diff mbox series

Patch

diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 9e4d7d884115..8b59632ec6b1 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -3058,7 +3058,6 @@  static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
 {
 	struct ice_pf *pf = (struct ice_pf *)data;
 	struct ice_hw *hw = &pf->hw;
-	irqreturn_t ret = IRQ_NONE;
 	struct device *dev;
 	u32 oicr, ena_mask;
 
@@ -3139,10 +3138,8 @@  static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
 
 	if (oicr & PFINT_OICR_TSYN_TX_M) {
 		ena_mask &= ~PFINT_OICR_TSYN_TX_M;
-		if (!hw->reset_ongoing) {
+		if (!hw->reset_ongoing)
 			pf->oicr_misc |= PFINT_OICR_TSYN_TX_M;
-			ret = IRQ_WAKE_THREAD;
-		}
 	}
 
 	if (oicr & PFINT_OICR_TSYN_EVNT_M) {
@@ -3159,7 +3156,6 @@  static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
 					       GLTSYN_STAT_EVENT2_M);
 
 			pf->oicr_misc |= PFINT_OICR_TSYN_EVNT_M;
-			ret = IRQ_WAKE_THREAD;
 		}
 	}
 
@@ -3180,16 +3176,12 @@  static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
 		if (oicr & (PFINT_OICR_PCI_EXCEPTION_M |
 			    PFINT_OICR_ECC_ERR_M)) {
 			set_bit(ICE_PFR_REQ, pf->state);
-			ice_service_task_schedule(pf);
 		}
 	}
-	if (!ret)
-		ret = IRQ_HANDLED;
 
-	ice_service_task_schedule(pf);
 	ice_irq_dynamic_ena(hw, NULL, NULL);
 
-	return ret;
+	return IRQ_WAKE_THREAD;
 }
 
 /**
@@ -3204,6 +3196,8 @@  static irqreturn_t ice_misc_intr_thread_fn(int __always_unused irq, void *data)
 	if (ice_is_reset_in_progress(pf->state))
 		return IRQ_HANDLED;
 
+	ice_service_task_schedule(pf);
+
 	if (pf->oicr_misc & PFINT_OICR_TSYN_EVNT_M) {
 		ice_ptp_extts_event(pf);
 		pf->oicr_misc &= ~PFINT_OICR_TSYN_EVNT_M;