qcacmn: Stop ROC timer synchronously

Mc timer is used to initialize the p2p roc timer.
And the actual timer runs in the soft irq thread and
when the timer exipres it posts the message to mc thread.
Currently, qdf_mc_timer_stop is called to stop the timer.
It calls the del_timer internally to delete the timer.
del_timer() ensures that the given timer is not queued
to run anywhere in the system. But the callback may
be running on another CPU core can create race conditions.

So use del_timer_sync to delete the roc timer.

Change-Id: I2c0fd6e335fc342a3acf06ede534c84d40e19346
CRs-Fixed: 2447236
diff --git a/qdf/inc/qdf_mc_timer.h b/qdf/inc/qdf_mc_timer.h
index 19ef611..5d94df6 100644
--- a/qdf/inc/qdf_mc_timer.h
+++ b/qdf/inc/qdf_mc_timer.h
@@ -227,6 +227,22 @@
 QDF_STATUS qdf_mc_timer_stop(qdf_mc_timer_t *timer);
 
 /**
+ * qdf_mc_timer_stop_sync() - stop a QDF Timer
+ * @timer: Pointer to timer object
+ * qdf_mc_timer_stop_sync() function stops a timer synchronously
+ * that has been started but has not expired, essentially
+ * cancelling the 'start' request.
+ *
+ * After a timer is stopped, it goes back to the state it was in after it
+ * was created and can be started again via a call to qdf_mc_timer_start().
+ *
+ * Return:
+ * QDF_STATUS_SUCCESS - Timer is initialized successfully
+ * QDF failure status - Timer initialization failed
+ */
+QDF_STATUS qdf_mc_timer_stop_sync(qdf_mc_timer_t *timer);
+
+/**
  * qdf_mc_timer_get_system_ticks() - get the system time in 10ms ticks
  *
  * qdf_mc_timer_get_system_ticks() function returns the current number
diff --git a/qdf/linux/src/qdf_mc_timer.c b/qdf/linux/src/qdf_mc_timer.c
index d69c668..d0baa3a 100644
--- a/qdf/linux/src/qdf_mc_timer.c
+++ b/qdf/linux/src/qdf_mc_timer.c
@@ -757,6 +757,47 @@
 }
 qdf_export_symbol(qdf_mc_timer_stop);
 
+QDF_STATUS qdf_mc_timer_stop_sync(qdf_mc_timer_t *timer)
+{
+	/* check for invalid pointer */
+	if (!timer) {
+		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
+			  "%s Null timer pointer being passed", __func__);
+		QDF_ASSERT(0);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	/* check if timer refers to an uninitialized object */
+	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
+		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
+			  "%s: Cannot stop uninitialized timer", __func__);
+		QDF_ASSERT(0);
+
+		return QDF_STATUS_E_INVAL;
+	}
+
+	/* ensure the timer state is correct */
+	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
+
+	if (QDF_TIMER_STATE_RUNNING != timer->state) {
+		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
+		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
+			  "%s: Cannot stop timer in state = %d",
+			  __func__, timer->state);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	timer->state = QDF_TIMER_STATE_STOPPED;
+
+	del_timer_sync(&(timer->platform_info.timer));
+
+	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
+
+	qdf_try_allowing_sleep(timer->type);
+
+	return QDF_STATUS_SUCCESS;
+}
+qdf_export_symbol(qdf_mc_timer_stop_sync);
 /**
  * qdf_mc_timer_get_system_ticks() - get the system time in 10ms ticks