File 23096-x86-hpet-no-cpumask_lock.patch of Package xen

# HG changeset patch
# User Jan Beulich <jbeulich@novell.com>
# Date 1301043797 0
# Node ID a65612bcbb921e98a8843157bf365e4ab16e8144
# Parent  941119d58655f2b2df86d9ecc4cb502bbc5e783c
x86/hpet: eliminate cpumask_lock

According to the (now getting removed) comment in struct
hpet_event_channel, this was to prevent accessing a CPU's
timer_deadline after it got cleared from cpumask. This can be done
without a lock altogether - hpet_broadcast_exit() can simply clear
the bit, and handle_hpet_broadcast() can read timer_deadline before
looking at the mask a second time (the cpumask bit was already
found set by the surrounding loop).

Signed-off-by: Jan Beulich <jbeulich@novell.com>
Acked-by: Gang Wei <gang.wei@intel.com>

Index: xen-4.1.2-testing/xen/arch/x86/hpet.c
===================================================================
--- xen-4.1.2-testing.orig/xen/arch/x86/hpet.c
+++ xen-4.1.2-testing/xen/arch/x86/hpet.c
@@ -34,18 +34,6 @@ struct hpet_event_channel
     int           shift;
     s_time_t      next_event;
     cpumask_t     cpumask;
-    /*
-     * cpumask_lock is used to prevent hpet intr handler from accessing other
-     * cpu's timer_deadline after the other cpu's mask was cleared --
-     * mask cleared means cpu waken up, then accessing timer_deadline from
-     * other cpu is not safe.
-     * It is not used for protecting cpumask, so set ops needn't take it.
-     * Multiple cpus clear cpumask simultaneously is ok due to the atomic
-     * feature of cpu_clear, so hpet_broadcast_exit() can take read lock for 
-     * clearing cpumask, and handle_hpet_broadcast() have to take write lock 
-     * for read cpumask & access timer_deadline.
-     */
-    rwlock_t      cpumask_lock;
     spinlock_t    lock;
     void          (*event_handler)(struct hpet_event_channel *);
 
@@ -208,17 +196,18 @@ again:
     /* find all expired events */
     for_each_cpu_mask(cpu, ch->cpumask)
     {
-        write_lock_irq(&ch->cpumask_lock);
+        s_time_t deadline;
 
-        if ( cpu_isset(cpu, ch->cpumask) )
-        {
-            if ( per_cpu(timer_deadline, cpu) <= now )
-                cpu_set(cpu, mask);
-            else if ( per_cpu(timer_deadline, cpu) < next_event )
-                next_event = per_cpu(timer_deadline, cpu);
-        }
+        rmb();
+        deadline = per_cpu(timer_deadline, cpu);
+        rmb();
+        if ( !cpu_isset(cpu, ch->cpumask) )
+            continue;
 
-        write_unlock_irq(&ch->cpumask_lock);
+        if ( deadline <= now )
+            cpu_set(cpu, mask);
+        else if ( deadline < next_event )
+            next_event = deadline;
     }
 
     /* wakeup the cpus which have an expired event. */
@@ -598,7 +587,6 @@ void hpet_broadcast_init(void)
             hpet_events[i].shift = 32;
             hpet_events[i].next_event = STIME_MAX;
             spin_lock_init(&hpet_events[i].lock);
-            rwlock_init(&hpet_events[i].cpumask_lock);
             wmb();
             hpet_events[i].event_handler = handle_hpet_broadcast;
         }
@@ -634,7 +622,6 @@ void hpet_broadcast_init(void)
     legacy_hpet_event.idx = 0;
     legacy_hpet_event.flags = 0;
     spin_lock_init(&legacy_hpet_event.lock);
-    rwlock_init(&legacy_hpet_event.cpumask_lock);
     wmb();
     legacy_hpet_event.event_handler = handle_hpet_broadcast;
 
@@ -716,9 +703,7 @@ void hpet_broadcast_exit(void)
     if ( !reprogram_timer(this_cpu(timer_deadline)) )
         raise_softirq(TIMER_SOFTIRQ);
 
-    read_lock_irq(&ch->cpumask_lock);
     cpu_clear(cpu, ch->cpumask);
-    read_unlock_irq(&ch->cpumask_lock);
 
     if ( ch != &legacy_hpet_event )
     {
openSUSE Build Service is sponsored by