94 lines
3.4 KiB
Diff
94 lines
3.4 KiB
Diff
|
# 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>
|
||
|
|
||
|
--- a/xen/arch/x86/hpet.c
|
||
|
+++ b/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;
|
||
|
|
||
|
@@ -713,9 +700,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 )
|
||
|
{
|