Commit f92fcb5c authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'ice-avoid-sleeping-scheduling-in-atomic-contexts'

Alexander Lobakin says:

====================
ice: avoid sleeping/scheduling in atomic contexts

The `ice_misc_intr() + ice_send_event_to_aux()` infamous pair failed
once again.
Fix yet another (hopefully last one) 'scheduling while atomic' splat
and finally plug the hole to gracefully return prematurely when
invoked in wrong context instead of panicking.
====================

Link: https://lore.kernel.org/r/20220323124353.2762181-1-alexandr.lobakin@intel.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 6a7d8cff 5a315693
...@@ -290,6 +290,7 @@ enum ice_pf_state { ...@@ -290,6 +290,7 @@ enum ice_pf_state {
ICE_LINK_DEFAULT_OVERRIDE_PENDING, ICE_LINK_DEFAULT_OVERRIDE_PENDING,
ICE_PHY_INIT_COMPLETE, ICE_PHY_INIT_COMPLETE,
ICE_FD_VF_FLUSH_CTX, /* set at FD Rx IRQ or timeout */ ICE_FD_VF_FLUSH_CTX, /* set at FD Rx IRQ or timeout */
ICE_AUX_ERR_PENDING,
ICE_STATE_NBITS /* must be last */ ICE_STATE_NBITS /* must be last */
}; };
...@@ -559,6 +560,7 @@ struct ice_pf { ...@@ -559,6 +560,7 @@ struct ice_pf {
wait_queue_head_t reset_wait_queue; wait_queue_head_t reset_wait_queue;
u32 hw_csum_rx_error; u32 hw_csum_rx_error;
u32 oicr_err_reg;
u16 oicr_idx; /* Other interrupt cause MSIX vector index */ u16 oicr_idx; /* Other interrupt cause MSIX vector index */
u16 num_avail_sw_msix; /* remaining MSIX SW vectors left unclaimed */ u16 num_avail_sw_msix; /* remaining MSIX SW vectors left unclaimed */
u16 max_pf_txqs; /* Total Tx queues PF wide */ u16 max_pf_txqs; /* Total Tx queues PF wide */
......
...@@ -34,6 +34,9 @@ void ice_send_event_to_aux(struct ice_pf *pf, struct iidc_event *event) ...@@ -34,6 +34,9 @@ void ice_send_event_to_aux(struct ice_pf *pf, struct iidc_event *event)
{ {
struct iidc_auxiliary_drv *iadrv; struct iidc_auxiliary_drv *iadrv;
if (WARN_ON_ONCE(!in_task()))
return;
if (!pf->adev) if (!pf->adev)
return; return;
......
...@@ -2255,6 +2255,19 @@ static void ice_service_task(struct work_struct *work) ...@@ -2255,6 +2255,19 @@ static void ice_service_task(struct work_struct *work)
return; return;
} }
if (test_and_clear_bit(ICE_AUX_ERR_PENDING, pf->state)) {
struct iidc_event *event;
event = kzalloc(sizeof(*event), GFP_KERNEL);
if (event) {
set_bit(IIDC_EVENT_CRIT_ERR, event->type);
/* report the entire OICR value to AUX driver */
swap(event->reg, pf->oicr_err_reg);
ice_send_event_to_aux(pf, event);
kfree(event);
}
}
if (test_bit(ICE_FLAG_PLUG_AUX_DEV, pf->flags)) { if (test_bit(ICE_FLAG_PLUG_AUX_DEV, pf->flags)) {
/* Plug aux device per request */ /* Plug aux device per request */
ice_plug_aux_dev(pf); ice_plug_aux_dev(pf);
...@@ -3041,17 +3054,9 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) ...@@ -3041,17 +3054,9 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
#define ICE_AUX_CRIT_ERR (PFINT_OICR_PE_CRITERR_M | PFINT_OICR_HMC_ERR_M | PFINT_OICR_PE_PUSH_M) #define ICE_AUX_CRIT_ERR (PFINT_OICR_PE_CRITERR_M | PFINT_OICR_HMC_ERR_M | PFINT_OICR_PE_PUSH_M)
if (oicr & ICE_AUX_CRIT_ERR) { if (oicr & ICE_AUX_CRIT_ERR) {
struct iidc_event *event; pf->oicr_err_reg |= oicr;
set_bit(ICE_AUX_ERR_PENDING, pf->state);
ena_mask &= ~ICE_AUX_CRIT_ERR; ena_mask &= ~ICE_AUX_CRIT_ERR;
event = kzalloc(sizeof(*event), GFP_ATOMIC);
if (event) {
set_bit(IIDC_EVENT_CRIT_ERR, event->type);
/* report the entire OICR value to AUX driver */
event->reg = oicr;
ice_send_event_to_aux(pf, event);
kfree(event);
}
} }
/* Report any remaining unexpected interrupts */ /* Report any remaining unexpected interrupts */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment