On PREEMPT_RT most items are processed as LAZY via softirq context. Avoid to spin-wait for them because irq_work_sync() could have higher priority and not allow the irq-work to be completed. Wait additionally for !IRQ_WORK_HARD_IRQ irq_work items on PREEMPT_RT.
Unified · Split
| @@ -49,6 +49,11 @@ static inline bool irq_work_is_busy(struct irq_work *work) · 48 unmodified lines | ||
| 49 | 49 | return atomic_read(&work->node.a_flags) & IRQ_WORK_BUSY; |
| 50 | 50 | } |
| 51 | 51 | |
| 52 | +static inline bool irq_work_is_hard(struct irq_work *work) | |
| 53 | +{ | |
| 54 | + return atomic_read(&work->node.a_flags) & IRQ_WORK_HARD_IRQ; | |
| 55 | +} | |
| 56 | + | |
| 52 | 57 | bool irq_work_queue(struct irq_work *work); |
| 53 | 58 | bool irq_work_queue_on(struct irq_work *work, int cpu); |
| 54 | 59 | |
| @@ -217,7 +217,8 @@ void irq_work_single(void *arg) · 216 unmodified lines | ||
| 217 | 217 | */ |
| 218 | 218 | (void)atomic_cmpxchg(&work->node.a_flags, flags, flags & ~IRQ_WORK_BUSY); |
| 219 | 219 | |
| 220 | − if (!arch_irq_work_has_interrupt()) | |
| 220 | + if ((IS_ENABLED(CONFIG_PREEMPT_RT) && !irq_work_is_hard(work)) || | |
| 221 | + !arch_irq_work_has_interrupt()) | |
| 221 | 222 | rcuwait_wake_up(&work->irqwait); |
| 222 | 223 | } |
| 223 | 224 | |
| @@ -277,7 +278,8 @@ void irq_work_sync(struct irq_work *work) · 53 unmodified lines | ||
| 277 | 278 | lockdep_assert_irqs_enabled(); |
| 278 | 279 | might_sleep(); |
| 279 | 280 | |
| 280 | − if (!arch_irq_work_has_interrupt()) { | |
| 281 | + if ((IS_ENABLED(CONFIG_PREEMPT_RT) && !irq_work_is_hard(work)) || | |
| 282 | + !arch_irq_work_has_interrupt()) { | |
| 281 | 283 | rcuwait_wait_event(&work->irqwait, !irq_work_is_busy(work), |
| 282 | 284 | TASK_UNINTERRUPTIBLE); |
| 283 | 285 | return; |