--- unstable.orig/xen/arch/x86/irq.c	2021-04-08 11:10:47.000000000 +0200
+++ unstable/xen/arch/x86/irq.c	2025-02-11 09:54:38.532567287 +0100
@@ -6,6 +6,7 @@
  */
 
 #include <xen/init.h>
+#include <xen/cpu.h>
 #include <xen/delay.h>
 #include <xen/errno.h>
 #include <xen/event.h>
@@ -1183,7 +1184,7 @@ static inline void clear_pirq_eoi(struct
     }
 }
 
-static void cf_check set_eoi_ready(void *data);
+static bool invoke_set_eoi_ready(struct irq_desc *desc, bool wait);
 
 static void cf_check irq_guest_eoi_timer_fn(void *data)
 {
@@ -1224,18 +1225,13 @@ static void cf_check irq_guest_eoi_timer
 
     switch ( action->ack_type )
     {
-        cpumask_t *cpu_eoi_map;
-
     case ACKTYPE_UNMASK:
         if ( desc->handler->end )
             desc->handler->end(desc, 0);
         break;
 
     case ACKTYPE_EOI:
-        cpu_eoi_map = this_cpu(scratch_cpumask);
-        cpumask_copy(cpu_eoi_map, action->cpu_eoi_map);
-        spin_unlock_irq(&desc->lock);
-        on_selected_cpus(cpu_eoi_map, set_eoi_ready, desc, 0);
+        invoke_set_eoi_ready(desc, false);
         return;
     }
 
@@ -1468,6 +1464,49 @@ static void cf_check set_eoi_ready(void
     flush_ready_eoi();
 }
 
+/*
+ * Locking is somewhat special here: In all cases the function is invoked with
+ * desc's lock held.  When @wait is true, the function tries to avoid unlocking.
+ * It always returns whether the lock is still held.
+ */
+static bool invoke_set_eoi_ready(struct irq_desc *desc, bool wait)
+{
+    const irq_guest_action_t *action = guest_action(desc);
+    cpumask_t cpu_eoi_map;
+
+    cpumask_copy(&cpu_eoi_map, action->cpu_eoi_map);
+
+    if ( __cpumask_test_and_clear_cpu(smp_processor_id(), &cpu_eoi_map) )
+    {
+        ASSERT(action->ack_type == ACKTYPE_EOI);
+        __set_eoi_ready(desc);
+        spin_unlock(&desc->lock);
+        flush_ready_eoi();
+        local_irq_enable();
+    }
+    else if ( wait && cpumask_empty(&cpu_eoi_map) )
+        return true;
+    else
+    {
+        ASSERT(action->ack_type == ACKTYPE_EOI);
+        spin_unlock_irq(&desc->lock);
+    }
+
+    if ( cpumask_empty(&cpu_eoi_map) )
+        return false;
+
+    while ( !get_cpu_maps() )
+        process_pending_softirqs();
+
+    cpumask_and(&cpu_eoi_map, &cpu_eoi_map, &cpu_online_map);
+    if ( !cpumask_empty(&cpu_eoi_map) )
+        on_selected_cpus(&cpu_eoi_map, set_eoi_ready, desc, wait);
+
+    put_cpu_maps();
+
+    return false;
+}
+
 void pirq_guest_eoi(struct pirq *pirq)
 {
     struct irq_desc *desc;
@@ -1481,7 +1520,6 @@ void pirq_guest_eoi(struct pirq *pirq)
 void desc_guest_eoi(struct irq_desc *desc, struct pirq *pirq)
 {
     irq_guest_action_t *action = guest_action(desc);
-    cpumask_t           cpu_eoi_map;
 
     if ( unlikely(!action) ||
          unlikely(!test_and_clear_bool(pirq->masked)) ||
@@ -1502,24 +1540,7 @@ void desc_guest_eoi(struct irq_desc *des
         return;
     }
 
-    ASSERT(action->ack_type == ACKTYPE_EOI);
-        
-    cpumask_copy(&cpu_eoi_map, action->cpu_eoi_map);
-
-    if ( __cpumask_test_and_clear_cpu(smp_processor_id(), &cpu_eoi_map) )
-    {
-        __set_eoi_ready(desc);
-        spin_unlock(&desc->lock);
-        flush_ready_eoi();
-        local_irq_enable();
-    }
-    else
-    {
-        spin_unlock_irq(&desc->lock);
-    }
-
-    if ( !cpumask_empty(&cpu_eoi_map) )
-        on_selected_cpus(&cpu_eoi_map, set_eoi_ready, desc, 0);
+    invoke_set_eoi_ready(desc, false);
 }
 
 int pirq_guest_unmask(struct domain *d)
@@ -1734,7 +1755,6 @@ static irq_guest_action_t *__pirq_guest_
     struct domain *d, struct pirq *pirq, struct irq_desc *desc)
 {
     irq_guest_action_t *action = guest_action(desc);
-    cpumask_t           cpu_eoi_map;
     int                 i;
 
     if ( unlikely(action == NULL) )
@@ -1765,12 +1785,7 @@ static irq_guest_action_t *__pirq_guest_
         if ( test_and_clear_bool(pirq->masked) &&
              (--action->in_flight == 0) &&
              (action->nr_guests != 0) )
-        {
-            cpumask_copy(&cpu_eoi_map, action->cpu_eoi_map);
-            spin_unlock_irq(&desc->lock);
-            on_selected_cpus(&cpu_eoi_map, set_eoi_ready, desc, 0);
-            spin_lock_irq(&desc->lock);
-        }
+            invoke_set_eoi_ready(desc, false);
         break;
     }
 
@@ -1796,14 +1811,8 @@ static irq_guest_action_t *__pirq_guest_
      * would need to flush all ready EOIs before returning as otherwise the
      * desc->handler could change and we would call the wrong 'end' hook.
      */
-    cpumask_copy(&cpu_eoi_map, action->cpu_eoi_map);
-    if ( !cpumask_empty(&cpu_eoi_map) )
-    {
-        BUG_ON(action->ack_type != ACKTYPE_EOI);
-        spin_unlock_irq(&desc->lock);
-        on_selected_cpus(&cpu_eoi_map, set_eoi_ready, desc, 1);
+    if ( !invoke_set_eoi_ready(desc, true) )
         spin_lock_irq(&desc->lock);
-    }
 
     BUG_ON(!cpumask_empty(action->cpu_eoi_map));
 
