event_timer: Add spinlock protection to event time update

Modify call flow to allow only one thread to make the smp cross call in
order to setup the event timer. Added more concurrency protections.
This helps fix a kernel data abort , where the stack looks like

Unable to handle kernel NULL pointer dereference at virtual address 0000008
pgd = d833c000
[00000008] *pgd=00000000
Internal error: Oops: 5 [#1] PREEMPT SMP ARM
Modules linked in: mwlan_aarp(PO)
CPU: 0    Tainted: P        W  O  (3.4.0-perf-gf36610b-dirty #3)
PC is at __rb_rotate_left+0xc/0x70
LR is at rb_insert_color+0x100/0x12c
pc : <c02400e8>    lr : <c02402c0>    psr: 00000093
sp : d7b4db58  ip : 00000000  fp : 400bf518
r10: c0e957b8  r9 : 0000047c  r8 : 00000000
r7 : c0dcc1fc  r6 : d8ed9900  r5 : d8ed9900  r4 : d8f55ac0
r3 : 00000000  r2 : d8f55ac0  r1 : c0dcc1fc  r0 : d8ed9900
Flags: nzcv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 10c5787d  Table: 98d3c06a  DAC: 00000015

(__rb_rotate_left+0xc/0x70) from (rb_insert_color+0x100/0x12c)
(rb_insert_color+0x100/0x12c) from (timerqueue_add+0x8c/0xbc)
(timerqueue_add+0x8c/0xbc) from (create_timer_smp+0x58/0xb8)
(create_timer_smp+0x58/0xb8) from (smp_call_function_single+0xc8/0x1c8)
(smp_call_function_single+0xc8/0x1c8) (mdp_update_pm+0xa4/0xb0)

The kernel data abort was likely due to a double add meaning adding the
same node twice, serializing the smp cross call should help this issue.

CRs-fixed: 442891
Change-Id: I572550b75ca18cdccc474103d863e8a924bccbba
Signed-off-by: Girish Mahadevan <girishm@codeaurora.org>
diff --git a/arch/arm/mach-msm/event_timer.c b/arch/arm/mach-msm/event_timer.c
index 9f46f68..df79e42 100644
--- a/arch/arm/mach-msm/event_timer.c
+++ b/arch/arm/mach-msm/event_timer.c
@@ -37,9 +37,9 @@
 	void *data;
 };
 
-
 static DEFINE_TIME_HEAD(timer_head);
 static DEFINE_SPINLOCK(event_timer_lock);
+static DEFINE_SPINLOCK(event_setup_lock);
 static struct hrtimer event_hrtimer;
 static enum hrtimer_restart event_hrtimer_cb(struct hrtimer *hrtimer);
 
@@ -73,6 +73,9 @@
 	event_info->data = data;
 	/* Init rb node and hr timer */
 	timerqueue_init(&event_info->node);
+	pr_debug("%s: New Event Added. Event 0x%x.",
+	__func__,
+	(unsigned int)event_info);
 
 	return event_info;
 }
@@ -140,10 +143,6 @@
 
 	event_hrtimer.function = event_hrtimer_cb;
 	hrtimer_start(&event_hrtimer, expires, HRTIMER_MODE_ABS);
-
-	if (msm_event_debug_mask && MSM_EVENT_TIMER_DEBUG)
-		pr_info("%s: Setting timer for %lu", __func__,
-			(unsigned long)ktime_to_ns(expires));
 }
 
 /**
@@ -155,7 +154,9 @@
 {
 	struct event_timer_info *event;
 	struct timerqueue_node *next;
+	unsigned long flags;
 
+	spin_lock_irqsave(&event_timer_lock, flags);
 	next = timerqueue_getnext(&timer_head);
 
 	while (next && (ktime_to_ns(next->expires)
@@ -168,7 +169,8 @@
 			goto hrtimer_cb_exit;
 
 		if (msm_event_debug_mask && MSM_EVENT_TIMER_DEBUG)
-			pr_info("%s: Deleting event @ %lu", __func__,
+			pr_info("%s: Deleting event 0x%x @ %lu", __func__,
+			(unsigned int)event,
 			(unsigned long)ktime_to_ns(next->expires));
 
 		timerqueue_del(&timer_head, &event->node);
@@ -181,6 +183,7 @@
 	if (next)
 		create_hrtimer(next->expires);
 
+	spin_unlock_irqrestore(&event_timer_lock, flags);
 hrtimer_cb_exit:
 	return HRTIMER_NORESTART;
 }
@@ -201,7 +204,10 @@
 
 	next = timerqueue_getnext(&timer_head);
 	timerqueue_add(&timer_head, &event->node);
-	spin_unlock_irqrestore(&event_timer_lock, flags);
+	if (msm_event_debug_mask && MSM_EVENT_TIMER_DEBUG)
+		pr_info("%s: Adding Event 0x%x for %lu", __func__,
+		(unsigned int)event,
+		(unsigned long)ktime_to_ns(event->node.expires));
 
 	if (!next ||
 		(next && (ktime_to_ns(event->node.expires) <
@@ -211,6 +217,7 @@
 			(unsigned long)ktime_to_ns(event->node.expires));
 		create_hrtimer(event->node.expires);
 	}
+	spin_unlock_irqrestore(&event_timer_lock, flags);
 }
 
 /**
@@ -239,9 +246,11 @@
 		pr_info("%s: Adding event timer @ %lu", __func__,
 				(unsigned long)ktime_to_us(event_time));
 
+	spin_lock(&event_setup_lock);
 	event->node.expires = event_time;
 	/* Start hr timer and add event to rb tree */
 	setup_event_hrtimer(event);
+	spin_unlock(&event_setup_lock);
 }