text: /*
   * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
   *
   * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
   *
   *
   * Permission to use, copy, modify, and/or distribute this software for
   * any purpose with or without fee is hereby granted, provided that the
   * above copyright notice and this permission notice appear in all
   * copies.
   *
   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
   * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
   * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
   * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
   * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
   * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
   * PERFORMANCE OF THIS SOFTWARE.
   */
  
  /*
   * This file was originally distributed by Qualcomm Atheros, Inc.
   * under proprietary terms before Copyright ownership was assigned
   * to the Linux Foundation.
   */
  
  /*===========================================================================
    @file vos_sched.c
    @brief VOS Scheduler Implementation
  ===========================================================================*/
  /*===========================================================================
                         EDIT HISTORY FOR FILE
  
    This section contains comments describing changes made to the module.
    Notice that changes are listed in reverse chronological order.
  
    $Header:$ $DateTime: $ $Author: $
  
    when        who    what, where, why
    --------    ---    --------------------------------------------------------
  ===========================================================================*/
  /*---------------------------------------------------------------------------
   * Include Files
   * ------------------------------------------------------------------------*/
  #include <vos_mq.h>
  #include <vos_api.h>
  #include <aniGlobal.h>
  #include <sirTypes.h>
  #include <halTypes.h>
  #include <limApi.h>
  #include <sme_Api.h>
  #include <wlan_qct_sys.h>
  #include <wlan_qct_tl.h>
  #include "vos_sched.h"
  #include <wlan_hdd_power.h>
  #include "wlan_qct_wda.h"
  #include <linux/spinlock.h>
  #include <linux/kthread.h>
  #include <linux/cpu.h>
  #include <linux/topology.h>
  #include "vos_cnss.h"
  
  /*---------------------------------------------------------------------------
   * Preprocessor Definitions and Constants
   * ------------------------------------------------------------------------*/
  #define VOS_SCHED_THREAD_HEART_BEAT    INFINITE
  /* Milli seconds to delay SSR thread when an Entry point is Active */
  #define SSR_WAIT_SLEEP_TIME 200
  #define LOAD_UNLOAD_WAIT_SLEEP_TIME 200
  /* MAX iteration count to wait for Entry point to exit before
   * we proceed with SSR in WD Thread
   */
  #define MAX_SSR_WAIT_ITERATIONS 200
  #define MAX_LOAD_UNLOAD_WAIT_ITERATIONS 50
  #define MAX_SSR_PROTECT_LOG (16)
  
  /* Timer value for detecting thread stuck issues */
  #define THREAD_STUCK_TIMER_VAL 10000 /* 10 seconds */
  #define THREAD_STUCK_THRESHOLD 3
  
  static atomic_t ssr_protect_entry_count;
  static atomic_t load_unload_protect_count;
  
  struct ssr_protect {
     const char* func;
     bool  free;
     uint32_t pid;
  };
  
  static spinlock_t ssr_protect_lock;
  static struct ssr_protect ssr_protect_log[MAX_SSR_PROTECT_LOG];
  
  /*---------------------------------------------------------------------------
   * Type Declarations
   * ------------------------------------------------------------------------*/
  /*---------------------------------------------------------------------------
   * Data definitions
   * ------------------------------------------------------------------------*/
  static pVosSchedContext gpVosSchedContext;
  static pVosWatchdogContext gpVosWatchdogContext;
  
  /*---------------------------------------------------------------------------
   * Forward declaration
   * ------------------------------------------------------------------------*/
  static int VosMCThread(void *Arg);
  static int VosWDThread(void *Arg);
  #ifdef QCA_CONFIG_SMP
  static int VosTlshimRxThread(void *arg);
  static unsigned long affine_cpu = 0;
  static VOS_STATUS vos_alloc_tlshim_pkt_freeq(pVosSchedContext pSchedContext);
  #endif
  extern v_VOID_t vos_core_return_msg(v_PVOID_t pVContext, pVosMsgWrapper pMsgWrapper);
  
  
  #ifdef QCA_CONFIG_SMP
  
  /*Maximum 2 clusters supported*/
  #define VOS_MAX_CPU_CLUSTERS 2
  
  #define VOS_CPU_CLUSTER_TYPE_LITTLE 0
  #define VOS_CPU_CLUSTER_TYPE_PERF 1
  
  /**
   * vos_sched_find_attach_cpu - find available cores and attach to required core
   * @pSchedContext:	wlan scheduler context
   * @high_throughput:	high throughput is required or not
   *
   * Find current online cores.
   * high troughput required and PERF core online, then attach to last PERF core
   * low throughput required or only little cores online, the attach any little
   * core
   *
   * Return: 0 success
   *         1 fail
   */
  static int vos_sched_find_attach_cpu(pVosSchedContext pSchedContext,
  	bool high_throughput)
  {
  	unsigned long *online_perf_cpu = NULL;
  	unsigned long *online_litl_cpu = NULL;
  	unsigned char perf_core_count = 0;
  	unsigned char litl_core_count = 0;
  	int vosMaxClusterId = 0;
  #if defined(WLAN_OPEN_SOURCE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
  	struct cpumask litl_mask;
  	unsigned long cpus;
  	int i;
  #endif
  
  	VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_LOW,
  		"%s: num possible cpu %d",
  		__func__, num_possible_cpus());
  
  
  	online_perf_cpu = vos_mem_malloc(
  		num_possible_cpus() * sizeof(unsigned long));
  	if (!online_perf_cpu) {
  		VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
  			"%s: perf cpu cache alloc fail", __func__);
  		return 1;
  	}
  	vos_mem_zero(online_perf_cpu,
  		num_possible_cpus() * sizeof(unsigned long));
  
  	online_litl_cpu = vos_mem_malloc(
  		num_possible_cpus() * sizeof(unsigned long));
  	if (!online_litl_cpu) {
  		VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
  			"%s: lttl cpu cache alloc fail", __func__);
  		vos_mem_free(online_perf_cpu);
  		return 1;
  	}
  	vos_mem_zero(online_litl_cpu,
  		num_possible_cpus() * sizeof(unsigned long));
  
  	/* Get Online perf CPU count */
  #if defined(WLAN_OPEN_SOURCE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
  	for_each_online_cpu(cpus) {
  		if ( topology_physical_package_id(cpus) > VOS_MAX_CPU_CLUSTERS) {
  			VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
  				"%s: can handle max %d clusters, returning...",
  				__func__, VOS_MAX_CPU_CLUSTERS);
  				goto err;
  			}
  
  		if (topology_physical_package_id(cpus) == VOS_CPU_CLUSTER_TYPE_PERF) {
  			online_perf_cpu[perf_core_count] = cpus;
  			perf_core_count++;
  		} else {
  			online_litl_cpu[litl_core_count] = cpus;
  			litl_core_count++;
  		}
  		vosMaxClusterId =  topology_physical_package_id(cpus);
  	}
  #else
  	vosMaxClusterId = 0;
  #endif
  
  	/* Single cluster system, not need to handle this */
  	if (0 == vosMaxClusterId) {
  		VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_LOW,
  		"%s: single cluster system. returning", __func__);
  		goto success;
  	}
  
  	if ((!litl_core_count) && (!perf_core_count)) {
  		VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
  			"%s: Both Cluster off, do nothing", __func__);
  		goto success;
  	}
  
  	if ((high_throughput && perf_core_count) || (!litl_core_count)) {
  		/* Attach RX thread to PERF CPU */
  		if (pSchedContext->rx_thread_cpu !=
  			online_perf_cpu[perf_core_count - 1]) {
  			if (vos_set_cpus_allowed_ptr(
  				pSchedContext->TlshimRxThread,
  				online_perf_cpu[perf_core_count - 1])) {
  				VOS_TRACE(VOS_MODULE_ID_VOSS,
  					VOS_TRACE_LEVEL_ERROR,
  					"%s: rx thread perf core set fail",
  					__func__);
  				goto err;
  			}
  			pSchedContext->rx_thread_cpu =
  				online_perf_cpu[perf_core_count - 1];
  		}
  	} else {
  
  #if defined(WLAN_OPEN_SOURCE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
  		/* Attach to any little core
  		 * Final decision should made by scheduler */
  
  		cpumask_clear(&litl_mask);
  		for (i = 0;
  			i < litl_core_count;
  			i++) {
  			cpumask_set_cpu(online_litl_cpu[i], &litl_mask);
  		}
  
  		set_cpus_allowed_ptr(pSchedContext->TlshimRxThread, &litl_mask);
  		pSchedContext->rx_thread_cpu = 0;
  #else
  		/* Attach RX thread to last little core CPU */
  		if (pSchedContext->rx_thread_cpu !=
  			online_litl_cpu[litl_core_count - 1]) {
  			if (vos_set_cpus_allowed_ptr(
  				pSchedContext->TlshimRxThread,
  				online_litl_cpu[litl_core_count - 1])) {
  				VOS_TRACE(VOS_MODULE_ID_VOSS,
  					VOS_TRACE_LEVEL_ERROR,
  					"%s: rx thread litl core set fail",
  					__func__);
  					goto err;
  			}
  			pSchedContext->rx_thread_cpu =
  				online_litl_cpu[litl_core_count - 1];
  		}
  #endif
  	}
  
  	VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
  		"%s: NUM PERF CORE %d, HIGH TPUTR REQ %d, RX THRE CPU %lu",
  		__func__, perf_core_count,
  		(int)pSchedContext->high_throughput_required,
  		pSchedContext->rx_thread_cpu);
  success:
  	vos_mem_free(online_perf_cpu);
  	vos_mem_free(online_litl_cpu);
  	return 0;
  
  err:
  	vos_mem_free(online_perf_cpu);
  	vos_mem_free(online_litl_cpu);
  	return 1;
  
  }
  
  /**
   * vos_sched_handle_cpu_hot_plug - cpu hotplug event handler
   *
   * cpu hotplug indication handler
   * will find online cores and will assign proper core based on perf requirement
   *
   * Return: 0 success
   *         1 fail
   */
  int vos_sched_handle_cpu_hot_plug(void)
  {
  	pVosSchedContext pSchedContext = get_vos_sched_ctxt();
  
  	if (!pSchedContext) {
  		VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
  			"%s: invalid context", __func__);
  		return 1;
  	}
  
  	if (vos_is_load_unload_in_progress(VOS_MODULE_ID_VOSS, NULL) ||
  		(vos_is_logp_in_progress(VOS_MODULE_ID_VOSS, NULL)))
  		return 0;
  
  	vos_lock_acquire(&pSchedContext->affinity_lock);
  	if (vos_sched_find_attach_cpu(pSchedContext,
  		pSchedContext->high_throughput_required)) {
  		VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
  			"%s: handle hot plug fail", __func__);
  		vos_lock_release(&pSchedContext->affinity_lock);
  		return 1;
  	}
  	vos_lock_release(&pSchedContext->affinity_lock);
  	return 0;
  }
  
  /**
   * vos_sched_handle_throughput_req - cpu throughput requirement handler
   * @high_tput_required:	high throughput is required or not
   *
   * high or low throughput indication ahndler
   * will find online cores and will assign proper core based on perf requirement
   *
   * Return: 0 success
   *         1 fail
   */
  int vos_sched_handle_throughput_req(bool high_tput_required)
  {
  	pVosSchedContext pSchedContext = get_vos_sched_ctxt();
  
  	if (!pSchedContext) {
  		VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
  			"%s: invalid context", __func__);
  		return 1;
  	}
  
  	if (vos_is_load_unload_in_progress(VOS_MODULE_ID_VOSS, NULL) ||
  		(vos_is_logp_in_progress(VOS_MODULE_ID_VOSS, NULL)))
  		return 0;
  
  	vos_lock_acquire(&pSchedContext->affinity_lock);
  	pSchedContext->high_throughput_required = high_tput_required;
  	if (vos_sched_find_attach_cpu(pSchedContext, high_tput_required)) {
  		VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
  			"%s: handle throughput req fail", __func__);
  		vos_lock_release(&pSchedContext->affinity_lock);
  		return 1;
  	}
  	vos_lock_release(&pSchedContext->affinity_lock);
  	return 0;
  }
  
  /**
   * __vos_cpu_hotplug_notify - cpu core on-off notification handler
   * @block:	notifier block
   * @state:	state of core
   * @hcpu:	target cpu core
   *
   * pre-registered core status change notify callback function
   * will handle only ONLINE, OFFLINE notification
   * based on cpu architecture, rx thread affinity will be different
   *
   * Return: 0 success
   *         1 fail
   */
  static int __vos_cpu_hotplug_notify(struct notifier_block *block,
                                    unsigned long state, void *hcpu)
  {
     unsigned long cpu = (unsigned long) hcpu;
     unsigned long pref_cpu = 0;
     pVosSchedContext pSchedContext = get_vos_sched_ctxt();
     int i;
     unsigned int multi_cluster;
     unsigned int num_cpus;
  #if defined(WLAN_OPEN_SOURCE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
     int cpus;
  #endif
  
     if ((NULL == pSchedContext) || (NULL == pSchedContext->TlshimRxThread))
         return NOTIFY_OK;
  
     if (vos_is_load_unload_in_progress(VOS_MODULE_ID_VOSS, NULL) ||
        (vos_is_logp_in_progress(VOS_MODULE_ID_VOSS, NULL)))
         return NOTIFY_OK;
  
     num_cpus = num_possible_cpus();
     VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_LOW,
               "%s: RX CORE %d, STATE %d, NUM CPUS %d",
                __func__, (int)affine_cpu, (int)state, num_cpus);
     multi_cluster = 0;
  
  #if defined(WLAN_OPEN_SOURCE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
  
     for_each_online_cpu(cpus) {
          multi_cluster =  topology_physical_package_id(cpus);
      }
  #endif
  
     if ((multi_cluster) &&
         ((CPU_ONLINE == state) || (CPU_DEAD == state))) {
        vos_sched_handle_cpu_hot_plug();
        return NOTIFY_OK;
     }
  
     switch (state) {
     case CPU_ONLINE:
         if (affine_cpu != 0)
             return NOTIFY_OK;
  
         for_each_online_cpu(i) {
             if (i == 0)
                 continue;
             pref_cpu = i;
                 break;
         }
         break;
     case CPU_DEAD:
         if (cpu != affine_cpu)
             return NOTIFY_OK;
  
         affine_cpu = 0;
         for_each_online_cpu(i) {
             if (i == 0)
                 continue;
             pref_cpu = i;
                 break;
         }
     }
  
     if (pref_cpu == 0)
         return NOTIFY_OK;
  
     if (!vos_set_cpus_allowed_ptr(pSchedContext->TlshimRxThread, pref_cpu))
         affine_cpu = pref_cpu;
  
     return NOTIFY_OK;
  }
  
  /**
   * vos_cpu_hotplug_notify - cpu core on-off notification handler wrapper
   * @block:	notifier block
   * @state:	state of core
   * @hcpu:	target cpu core
   *
   * pre-registered core status change notify callback function
   * will handle only ONLINE, OFFLINE notification
   * based on cpu architecture, rx thread affinity will be different
   * wrapper function
   *
   * Return: 0 success
   *         1 fail
   */
  static int vos_cpu_hotplug_notify(struct notifier_block *block,
                                    unsigned long state, void *hcpu)
  {
  	int ret;
  
  	vos_ssr_protect(__func__);
  	ret = __vos_cpu_hotplug_notify(block, state, hcpu);
  	vos_ssr_unprotect(__func__);
  
  	return ret;
  }
  
  static struct notifier_block vos_cpu_hotplug_notifier = {
     .notifier_call = vos_cpu_hotplug_notify,
  };
  #endif
  
  /*---------------------------------------------------------------------------
   * External Function implementation
   * ------------------------------------------------------------------------*/
  
  /*---------------------------------------------------------------------------
    \brief vos_sched_open() - initialize the vOSS Scheduler
    The \a vos_sched_open() function initializes the vOSS Scheduler
    Upon successful initialization:
       - All the message queues are initialized
       - The Main Controller thread is created and ready to receive and
         dispatch messages.
       - The Tx thread is created and ready to receive and dispatch messages
  
    \param  pVosContext - pointer to the global vOSS Context
    \param  pVosSchedContext - pointer to a previously allocated buffer big
            enough to hold a scheduler context.
    \return VOS_STATUS_SUCCESS - Scheduler was successfully initialized and
            is ready to be used.
            VOS_STATUS_E_RESOURCES - System resources (other than memory)
            are unavailable to initilize the scheduler
            VOS_STATUS_E_NOMEM - insufficient memory exists to initialize
            the scheduler
            VOS_STATUS_E_INVAL - Invalid parameter passed to the scheduler Open
            function
            VOS_STATUS_E_FAILURE - Failure to initialize the scheduler/
    \sa vos_sched_open()
    -------------------------------------------------------------------------*/
  VOS_STATUS
  vos_sched_open
  (
    v_PVOID_t        pVosContext,
    pVosSchedContext pSchedContext,
    v_SIZE_t         SchedCtxSize
  )
  {
    VOS_STATUS  vStatus = VOS_STATUS_SUCCESS;
  #ifdef CONFIG_PERF_NON_QC_PLATFORM
    struct sched_param param = {.sched_priority = 99};
  #endif
  /*-------------------------------------------------------------------------*/
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
               "%s: Opening the VOSS Scheduler",__func__);
    // Sanity checks
    if ((pVosContext == NULL) || (pSchedContext == NULL)) {
       VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
               "%s: Null params being passed",__func__);
       return VOS_STATUS_E_FAILURE;
    }
    if (sizeof(VosSchedContext) != SchedCtxSize)
    {
       VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
                 "%s: Incorrect VOS Sched Context size passed",__func__);
       return VOS_STATUS_E_INVAL;
    }
    vos_mem_zero(pSchedContext, sizeof(VosSchedContext));
    pSchedContext->pVContext = pVosContext;
    vStatus = vos_sched_init_mqs(pSchedContext);
    if (!VOS_IS_STATUS_SUCCESS(vStatus))
    {
       VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                 "%s: Failed to initialize VOS Scheduler MQs",__func__);
       return vStatus;
    }
    // Initialize the helper events and event queues
    init_completion(&pSchedContext->McStartEvent);
    init_completion(&pSchedContext->McShutdown);
    init_completion(&pSchedContext->ResumeMcEvent);
  
    spin_lock_init(&pSchedContext->McThreadLock);
  #ifdef QCA_CONFIG_SMP
    spin_lock_init(&pSchedContext->TlshimRxThreadLock);
  #endif
  
    init_waitqueue_head(&pSchedContext->mcWaitQueue);
    pSchedContext->mcEventFlag = 0;
  
  #ifdef QCA_CONFIG_SMP
    init_waitqueue_head(&pSchedContext->tlshimRxWaitQueue);
    init_completion(&pSchedContext->TlshimRxStartEvent);
    init_completion(&pSchedContext->SuspndTlshimRxEvent);
    init_completion(&pSchedContext->ResumeTlshimRxEvent);
    init_completion(&pSchedContext->TlshimRxShutdown);
    pSchedContext->tlshimRxEvtFlg = 0;
    spin_lock_init(&pSchedContext->TlshimRxQLock);
    spin_lock_init(&pSchedContext->VosTlshimPktFreeQLock);
    INIT_LIST_HEAD(&pSchedContext->tlshimRxQueue);
    SPIN_LOCK_BH(&pSchedContext->VosTlshimPktFreeQLock);
    INIT_LIST_HEAD(&pSchedContext->VosTlshimPktFreeQ);
    if (vos_alloc_tlshim_pkt_freeq(pSchedContext) !=  VOS_STATUS_SUCCESS)
    {
         SPIN_UNLOCK_BH(&pSchedContext->VosTlshimPktFreeQLock);
         return VOS_STATUS_E_FAILURE;
    }
    SPIN_UNLOCK_BH(&pSchedContext->VosTlshimPktFreeQLock);
    //register_hotcpu_notifier(&vos_cpu_hotplug_notifier);
    //pSchedContext->cpuHotPlugNotifier = &vos_cpu_hotplug_notifier;
    vos_lock_init(&pSchedContext->affinity_lock);
    pSchedContext->high_throughput_required = false;
  #endif
  
  
    /*
    ** This initialization is critical as the threads will later access the
    ** global contexts normally,
    **
    ** I shall put some memory barrier here after the next piece of code but
    ** I am keeping it simple for now.
    */
    gpVosSchedContext = pSchedContext;
  
    //Create the VOSS Main Controller thread
    pSchedContext->McThread = kthread_create(VosMCThread, pSchedContext,
                                             "VosMCThread");
    if (IS_ERR(pSchedContext->McThread))
    {
       VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
                 "%s: Could not Create VOSS Main Thread Controller",__func__);
       goto MC_THREAD_START_FAILURE;
    }
    wake_up_process(pSchedContext->McThread);
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
              "%s: VOSS Main Controller thread Created",__func__);
  
  #ifdef QCA_CONFIG_SMP
    pSchedContext->TlshimRxThread = kthread_create(VosTlshimRxThread,
                                                   pSchedContext,
                                                   "VosTlshimRxThread");
  #ifdef CONFIG_PERF_NON_QC_PLATFORM
    sched_setscheduler(pSchedContext->TlshimRxThread, SCHED_FIFO, &param);
  #endif
    if (IS_ERR(pSchedContext->TlshimRxThread))
    {
  
       VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
                 "%s: Could not Create VOSS Tlshim RX Thread", __func__);
       goto TLSHIM_RX_THREAD_START_FAILURE;
  
    }
    wake_up_process(pSchedContext->TlshimRxThread);
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
               ("VOSS Tlshim RX thread Created"));
  #endif
    /*
    ** Now make sure all threads have started before we exit.
    ** Each thread should normally ACK back when it starts.
    */
    wait_for_completion_interruptible(&pSchedContext->McStartEvent);
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
                 "%s: VOSS MC Thread has started",__func__);
  #ifdef QCA_CONFIG_SMP
    wait_for_completion_interruptible(&pSchedContext->TlshimRxStartEvent);
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
                 "%s: VOSS Tlshim Rx Thread has started", __func__);
  #endif
    /*
    ** We're good now: Let's get the ball rolling!!!
    */
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
              "%s: VOSS Scheduler successfully Opened",__func__);
    return VOS_STATUS_SUCCESS;
  
  
  #ifdef QCA_CONFIG_SMP
  TLSHIM_RX_THREAD_START_FAILURE:
  #endif
  MC_THREAD_START_FAILURE:
      //Try and force the Main thread controller to exit
      set_bit(MC_SHUTDOWN_EVENT, &pSchedContext->mcEventFlag);
      set_bit(MC_POST_EVENT, &pSchedContext->mcEventFlag);
      wake_up_interruptible(&pSchedContext->mcWaitQueue);
      //Wait for MC to exit
      wait_for_completion_interruptible(&pSchedContext->McShutdown);
  
    //De-initialize all the message queues
    vos_sched_deinit_mqs(pSchedContext);
  
  
  #ifdef QCA_CONFIG_SMP
    //unregister_hotcpu_notifier(&vos_cpu_hotplug_notifier);
    vos_free_tlshim_pkt_freeq(gpVosSchedContext);
  #endif
  
    return VOS_STATUS_E_RESOURCES;
  
  } /* vos_sched_open() */
  
  VOS_STATUS vos_watchdog_open
  (
    v_PVOID_t           pVosContext,
    pVosWatchdogContext pWdContext,
    v_SIZE_t            wdCtxSize
  )
  {
  /*-------------------------------------------------------------------------*/
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
               "%s: Opening the VOSS Watchdog module",__func__);
    //Sanity checks
    if ((pVosContext == NULL) || (pWdContext == NULL)) {
       VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
               "%s: Null params being passed",__func__);
       return VOS_STATUS_E_FAILURE;
    }
    if (sizeof(VosWatchdogContext) != wdCtxSize)
    {
       VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
                 "%s: Incorrect VOS Watchdog Context size passed",__func__);
       return VOS_STATUS_E_INVAL;
    }
    vos_mem_zero(pWdContext, sizeof(VosWatchdogContext));
    pWdContext->pVContext = pVosContext;
    gpVosWatchdogContext = pWdContext;
    pWdContext->thread_stuck_timer.state = VOS_TIMER_STATE_UNUSED;
  
    //Initialize the helper events and event queues
    init_completion(&pWdContext->WdStartEvent);
    init_completion(&pWdContext->WdShutdown);
    init_waitqueue_head(&pWdContext->wdWaitQueue);
    pWdContext->wdEventFlag = 0;
  
    // Initialize the lock
    spin_lock_init(&pWdContext->wdLock);
    spin_lock_init(&pWdContext->thread_stuck_lock);
  
    //Create the Watchdog thread
    pWdContext->WdThread = kthread_create(VosWDThread, pWdContext,"VosWDThread");
  
    if (IS_ERR(pWdContext->WdThread))
    {
       VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
                 "%s: Could not Create Watchdog thread",__func__);
       return VOS_STATUS_E_RESOURCES;
    }
    else
    {
       wake_up_process(pWdContext->WdThread);
    }
   /*
    ** Now make sure thread has started before we exit.
    ** Each thread should normally ACK back when it starts.
    */
    wait_for_completion_interruptible(&pWdContext->WdStartEvent);
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
                 "%s: VOSS Watchdog Thread has started",__func__);
    return VOS_STATUS_SUCCESS;
  } /* vos_watchdog_open() */
  /*---------------------------------------------------------------------------
    \brief VosMcThread() - The VOSS Main Controller thread
    The \a VosMcThread() is the VOSS main controller thread:
    \param  Arg - pointer to the global vOSS Sched Context
    \return Thread exit code
    \sa VosMcThread()
    -------------------------------------------------------------------------*/
  static int
  VosMCThread
  (
    void * Arg
  )
  {
    pVosSchedContext pSchedContext = (pVosSchedContext)Arg;
    pVosMsgWrapper pMsgWrapper     = NULL;
    tpAniSirGlobal pMacContext     = NULL;
    tSirRetStatus macStatus        = eSIR_SUCCESS;
    VOS_STATUS vStatus             = VOS_STATUS_SUCCESS;
    int retWaitStatus              = 0;
    v_BOOL_t shutdown              = VOS_FALSE;
    hdd_context_t *pHddCtx         = NULL;
    v_CONTEXT_t pVosContext        = NULL;
  
    if (Arg == NULL)
    {
       VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
          "%s: Bad Args passed", __func__);
       return 0;
    }
    set_user_nice(current, -2);
  
  #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
    daemonize("MC_Thread");
  #endif
  
    /*
    ** Ack back to the context from which the main controller thread has been
    ** created.
    */
    complete(&pSchedContext->McStartEvent);
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
        "%s: MC Thread %d (%s) starting up",__func__, current->pid, current->comm);
  
    /* Get the Global VOSS Context */
    pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
    if(!pVosContext) {
       hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__);
       return 0;
    }
  
    /* Get the HDD context */
    pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext );
    if(!pHddCtx) {
       hddLog(VOS_TRACE_LEVEL_FATAL,"%s: HDD context is Null",__func__);
       return 0;
    }
  
    while(!shutdown)
    {
      // This implements the execution model algorithm
      retWaitStatus = wait_event_interruptible(pSchedContext->mcWaitQueue,
         test_bit(MC_POST_EVENT, &pSchedContext->mcEventFlag) ||
         test_bit(MC_SUSPEND_EVENT, &pSchedContext->mcEventFlag));
  
      if(retWaitStatus == -ERESTARTSYS)
      {
        VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
           "%s: wait_event_interruptible returned -ERESTARTSYS", __func__);
        VOS_BUG(0);
      }
      clear_bit(MC_POST_EVENT, &pSchedContext->mcEventFlag);
  
      while(1)
      {
        // Check if MC needs to shutdown
        if(test_bit(MC_SHUTDOWN_EVENT, &pSchedContext->mcEventFlag))
        {
          VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
                  "%s: MC thread signaled to shutdown", __func__);
          shutdown = VOS_TRUE;
          /* Check for any Suspend Indication */
          if(test_bit(MC_SUSPEND_EVENT, &pSchedContext->mcEventFlag))
          {
             clear_bit(MC_SUSPEND_EVENT, &pSchedContext->mcEventFlag);
  
             /* Unblock anyone waiting on suspend */
             complete(&pHddCtx->mc_sus_event_var);
          }
          break;
        }
  
        // Check the SYS queue first
        if (!vos_is_mq_empty(&pSchedContext->sysMcMq))
        {
          // Service the SYS message queue
          VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
                    "%s: Servicing the VOS SYS MC Message queue",__func__);
          pMsgWrapper = vos_mq_get(&pSchedContext->sysMcMq);
          if (pMsgWrapper == NULL)
          {
             VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: pMsgWrapper is NULL", __func__);
             VOS_ASSERT(0);
             break;
          }
          vStatus = sysMcProcessMsg(pSchedContext->pVContext,
             pMsgWrapper->pVosMsg);
          if (!VOS_IS_STATUS_SUCCESS(vStatus))
          {
             VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                       "%s: Issue Processing SYS message",__func__);
          }
          //return message to the Core
          vos_core_return_msg(pSchedContext->pVContext, pMsgWrapper);
          continue;
        }
        // Check the WDA queue
        if (!vos_is_mq_empty(&pSchedContext->wdaMcMq))
        {
          // Service the WDA message queue
          VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
                   "%s: Servicing the VOS WDA MC Message queue",__func__);
          pMsgWrapper = vos_mq_get(&pSchedContext->wdaMcMq);
          if (pMsgWrapper == NULL)
          {
             VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: pMsgWrapper is NULL", __func__);
             VOS_ASSERT(0);
             break;
          }
          vStatus = WDA_McProcessMsg( pSchedContext->pVContext, pMsgWrapper->pVosMsg);
          if (!VOS_IS_STATUS_SUCCESS(vStatus))
          {
             VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                       "%s: Issue Processing WDA message",__func__);
          }
          // return message to the Core
          vos_core_return_msg(pSchedContext->pVContext, pMsgWrapper);
          continue;
        }
        // Check the PE queue
        if (!vos_is_mq_empty(&pSchedContext->peMcMq))
        {
          // Service the PE message queue
          VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
                    "%s: Servicing the VOS PE MC Message queue",__func__);
          pMsgWrapper = vos_mq_get(&pSchedContext->peMcMq);
          if (NULL == pMsgWrapper)
          {
             VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: pMsgWrapper is NULL", __func__);
             VOS_ASSERT(0);
             break;
          }
  
          /* Need some optimization*/
          pMacContext = vos_get_context(VOS_MODULE_ID_PE, pSchedContext->pVContext);
          if (NULL == pMacContext)
          {
             VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
                       "MAC Context not ready yet");
             vos_core_return_msg(pSchedContext->pVContext, pMsgWrapper);
             continue;
          }
  
          macStatus = peProcessMessages( pMacContext, (tSirMsgQ*)pMsgWrapper->pVosMsg);
          if (eSIR_SUCCESS != macStatus)
          {
            VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                       "%s: Issue Processing PE message",__func__);
          }
          // return message to the Core
          vos_core_return_msg(pSchedContext->pVContext, pMsgWrapper);
          continue;
        }
        /** Check the SME queue **/
        if (!vos_is_mq_empty(&pSchedContext->smeMcMq))
        {
          /* Service the SME message queue */
          VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
                    "%s: Servicing the VOS SME MC Message queue",__func__);
          pMsgWrapper = vos_mq_get(&pSchedContext->smeMcMq);
          if (NULL == pMsgWrapper)
          {
             VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                 "%s: pMsgWrapper is NULL", __func__);
             VOS_ASSERT(0);
             break;
          }
  
          /* Need some optimization*/
          pMacContext = vos_get_context(VOS_MODULE_ID_SME, pSchedContext->pVContext);
          if (NULL == pMacContext)
          {
             VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
                       "MAC Context not ready yet");
             vos_core_return_msg(pSchedContext->pVContext, pMsgWrapper);
             continue;
          }
  
          vStatus = sme_ProcessMsg( (tHalHandle)pMacContext, pMsgWrapper->pVosMsg);
          if (!VOS_IS_STATUS_SUCCESS(vStatus))
          {
            VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                       "%s: Issue Processing SME message",__func__);
          }
          // return message to the Core
          vos_core_return_msg(pSchedContext->pVContext, pMsgWrapper);
          continue;
        }
        /** Check the TL queue **/
        if (!vos_is_mq_empty(&pSchedContext->tlMcMq))
        {
          // Service the TL message queue
          VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
                    ("Servicing the VOS TL MC Message queue"));
          pMsgWrapper = vos_mq_get(&pSchedContext->tlMcMq);
          if (pMsgWrapper == NULL)
          {
             VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: pMsgWrapper is NULL", __func__);
             VOS_ASSERT(0);
             break;
          }
          vStatus = WLANTL_McProcessMsg( pSchedContext->pVContext,
              pMsgWrapper->pVosMsg);
          if (!VOS_IS_STATUS_SUCCESS(vStatus))
          {
            VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                       "%s: Issue Processing TL message",__func__);
          }
          // return message to the Core
          vos_core_return_msg(pSchedContext->pVContext, pMsgWrapper);
          continue;
        }
        /* Check for any Suspend Indication */
        if(test_bit(MC_SUSPEND_EVENT, &pSchedContext->mcEventFlag))
        {
          clear_bit(MC_SUSPEND_EVENT, &pSchedContext->mcEventFlag);
          spin_lock(&pSchedContext->McThreadLock);
  
          INIT_COMPLETION(pSchedContext->ResumeMcEvent);
          /* Mc Thread Suspended */
          complete(&pHddCtx->mc_sus_event_var);
  
          spin_unlock(&pSchedContext->McThreadLock);
  
          /* Wait foe Resume Indication */
          wait_for_completion_interruptible(&pSchedContext->ResumeMcEvent);
        }
        break; //All queues are empty now
      } // while message loop processing
    } // while TRUE
    // If we get here the MC thread must exit
    VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
        "%s: MC Thread exiting!!!!", __func__);
    complete_and_exit(&pSchedContext->McShutdown, 0);
  } /* VosMCThread() */
  
  v_BOOL_t isWDresetInProgress(void)
  {
     if(gpVosWatchdogContext!=NULL)
     {
        return gpVosWatchdogContext->resetInProgress;
     }
     else
     {
        return FALSE;
     }
  }
  
   /**
   * vos_wd_detect_thread_stuck()- Detect thread stuck
   * by probing MC thread and take action if Thread doesnt respond.
   *
   * This function is called to detect thread stuck
   * and probe threads.
   *
   * Return: void
   */
  static void vos_wd_detect_thread_stuck(void)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&gpVosWatchdogContext->thread_stuck_lock, flags);
  
  	if (gpVosWatchdogContext->mc_thread_stuck_count ==
  				THREAD_STUCK_THRESHOLD) {
  		spin_unlock_irqrestore(&gpVosWatchdogContext->thread_stuck_lock,
  				flags);
  		hddLog(LOGE, FL("MC Thread Stuck!!!"));
  
  		vos_dump_stack(gpVosSchedContext->McThread);
  		vos_flush_logs(WLAN_LOG_TYPE_FATAL,
  			       WLAN_LOG_INDICATOR_HOST_ONLY,
  			       WLAN_LOG_REASON_THREAD_STUCK,
  			       DUMP_VOS_TRACE);
  		spin_lock_irqsave(&gpVosWatchdogContext->thread_stuck_lock,
  			flags);
  	}
  
  	/* Increment the thread stuck count for all threads */
  	gpVosWatchdogContext->mc_thread_stuck_count++;
  
  	if (gpVosWatchdogContext->mc_thread_stuck_count <=
  				THREAD_STUCK_THRESHOLD) {
  		spin_unlock_irqrestore(&gpVosWatchdogContext->thread_stuck_lock,
  				flags);
  		vos_probe_threads();
  	} else
  		spin_unlock_irqrestore(&gpVosWatchdogContext->thread_stuck_lock,
  				flags);
  
  	/* Restart the timer */
  	if (VOS_STATUS_SUCCESS !=
  		    vos_timer_start(&gpVosWatchdogContext->thread_stuck_timer,
  				THREAD_STUCK_TIMER_VAL))
  		hddLog(LOGE, FL("Unable to start thread stuck timer"));
  }
  
   /**
   * vos_wd_detect_thread_stuck_cb()- Call back of the
   * thread stuck timer.
   * @priv: timer data.
   * This function is called when the thread stuck timer
   * expire to detect thread stuck and probe threads.
   *
   * Return: void
   */
  static void vos_wd_detect_thread_stuck_cb(void *priv)
  {
  	if (!(vos_is_logp_in_progress(VOS_MODULE_ID_SYS, NULL) ||
  				vos_is_load_unload_in_progress(VOS_MODULE_ID_SYS
  					, NULL))) {
  		set_bit(WD_WLAN_DETECT_THREAD_STUCK,
  				&gpVosWatchdogContext->wdEventFlag);
  		set_bit(WD_POST_EVENT, &gpVosWatchdogContext->wdEventFlag);
  		wake_up_interruptible(&gpVosWatchdogContext->wdWaitQueue);
  	}
  }
  
   /**
   * vos_thread_stuck_timer_init - Initialize thread stuck timer
   *
   * @wd_ctx: watchdog context.
   *
   * Return: void
   */
  void vos_thread_stuck_timer_init(pVosWatchdogContext wd_ctx)
  {
      if (vos_timer_init(&wd_ctx->thread_stuck_timer,
                         VOS_TIMER_TYPE_SW,
                         vos_wd_detect_thread_stuck_cb, NULL))
          hddLog(LOGE, FL("Unable to initialize thread stuck timer"));
      else
      {
          if (VOS_STATUS_SUCCESS !=
                   vos_timer_start(&wd_ctx->thread_stuck_timer,
                                   THREAD_STUCK_TIMER_VAL))
              hddLog(LOGE, FL("Unable to start thread stuck timer"));
          else
              hddLog(LOG1, FL("Successfully started thread stuck timer"));
      }
  }
  
  /**
   * vos_wd_reset_thread_stuck_count()- Callback to
   * probe msg sent to Threads.
   *
   * @thread_id: passed threadid
   *
   * This function is called to by the thread after
   * processing the probe msg, with their own thread id.
   *
   * Return: void.
   */
  void vos_wd_reset_thread_stuck_count(int thread_id)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&gpVosWatchdogContext->thread_stuck_lock, flags);
  	if (vos_sched_is_mc_thread(thread_id))
  		gpVosWatchdogContext->mc_thread_stuck_count = 0;
  
  	spin_unlock_irqrestore(&gpVosWatchdogContext->thread_stuck_lock, flags);
  }
  
  /*---------------------------------------------------------------------------
    \brief VosWdThread() - The VOSS Watchdog thread
    The \a VosWdThread() is the Watchdog thread:
    \param  Arg - pointer to the global vOSS Sched Context
    \return Thread exit code
    \sa VosMcThread()
    -------------------------------------------------------------------------*/
  static int
  VosWDThread
  (
    void * Arg
  )
  {
    pVosWatchdogContext pWdContext = (pVosWatchdogContext)Arg;
    int retWaitStatus              = 0;
    v_BOOL_t shutdown              = VOS_FALSE;
    int count                      = 0;
    VOS_STATUS vosStatus = VOS_STATUS_SUCCESS;
    set_user_nice(current, -4);
  
    if (Arg == NULL)
    {
       VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
          "%s: Bad Args passed", __func__);
       return 0;
    }
  
  #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
    daemonize("WD_Thread");
  #endif
    /*
    ** Ack back to the context from which the Watchdog thread has been
    ** created.
    */
    complete(&pWdContext->WdStartEvent);
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
        "%s: Watchdog Thread %d (%s) starting up",__func__, current->pid, current->comm);
  
    while(!shutdown)
    {
      // This implements the Watchdog execution model algorithm
      retWaitStatus = wait_event_interruptible(pWdContext->wdWaitQueue,
         test_bit(WD_POST_EVENT, &pWdContext->wdEventFlag));
      if(retWaitStatus == -ERESTARTSYS)
      {
        VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
           "%s: wait_event_interruptible returned -ERESTARTSYS", __func__);
        break;
      }
      clear_bit(WD_POST_EVENT, &pWdContext->wdEventFlag);
      while(1)
      {
        /* Post Msg to detect thread stuck */
        if (test_and_clear_bit(WD_WLAN_DETECT_THREAD_STUCK,
                                     &pWdContext->wdEventFlag)) {
  
         if (!test_bit(MC_SUSPEND_EVENT, &gpVosSchedContext->mcEventFlag))
              vos_wd_detect_thread_stuck();
         else
              VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
                 "%s: controller thread %s id: %d is suspended do not attemp probing",
                 __func__, current->comm, current->pid);
          /*
           * Process here and return without processing any SSR
           * related logic.
           */
          break;
        }
        /* Check for any Active Entry Points
         * If active, delay SSR until no entry point is active or
         * delay until count is decremented to ZERO
         */
        count = MAX_SSR_WAIT_ITERATIONS;
        while (count)
        {
           if (!atomic_read(&ssr_protect_entry_count))
           {
               /* no external threads are executing */
               break;
           }
           /* at least one external thread is executing */
           if (--count)
           {
               VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                         "%s: Waiting for active entry points to exit", __func__);
               msleep(SSR_WAIT_SLEEP_TIME);
           }
        }
        /* at least one external thread is executing */
        if (!count)
        {
            VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                      "%s: Continuing SSR when %d Entry points are still active",
                       __func__, atomic_read(&ssr_protect_entry_count));
        }
        // Check if Watchdog needs to shutdown
        if(test_bit(WD_SHUTDOWN_EVENT, &pWdContext->wdEventFlag))
        {
          VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
                  "%s: Watchdog thread signaled to shutdown", __func__);
  
          clear_bit(WD_SHUTDOWN_EVENT, &pWdContext->wdEventFlag);
          shutdown = VOS_TRUE;
          break;
        }
        /* subsystem restart: shutdown event handler */
        else if(test_bit(WD_WLAN_SHUTDOWN_EVENT, &pWdContext->wdEventFlag))
        {
          VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
                  "%s: Watchdog thread signaled to perform WLAN shutdown",__func__);
          clear_bit(WD_WLAN_SHUTDOWN_EVENT, &pWdContext->wdEventFlag);
  
          //Perform WLAN shutdown
          if(!pWdContext->resetInProgress)
          {
            pWdContext->resetInProgress = true;
            vosStatus = hdd_wlan_shutdown();
  
            if (! VOS_IS_STATUS_SUCCESS(vosStatus))
            {
               VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
                       "%s: Failed to shutdown WLAN",__func__);
               VOS_ASSERT(0);
               goto err_reset;
            }
          }
        }
        /* subsystem restart: re-init event handler */
        else if(test_bit(WD_WLAN_REINIT_EVENT, &pWdContext->wdEventFlag))
        {
          VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
                  "%s: Watchdog thread signaled to perform WLAN re-init",__func__);
          clear_bit(WD_WLAN_REINIT_EVENT, &pWdContext->wdEventFlag);
  
          //Perform WLAN re-init
          if(!pWdContext->resetInProgress)
          {
            VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
            "%s: Trying to do WLAN re-init when it is not shutdown !!",__func__);
          }
          vosStatus = hdd_wlan_re_init(NULL);
  
          if (! VOS_IS_STATUS_SUCCESS(vosStatus))
          {
            VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
                    "%s: Failed to re-init WLAN",__func__);
            VOS_ASSERT(0);
            goto err_reset;
          }
          pWdContext->resetInProgress = false;
        }
        else
        {
          //Unnecessary wakeup - Should never happen!!
          VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
          "%s: Watchdog thread woke up unnecessarily",__func__);
        }
        break;
      } // while message loop processing
    } // while shutdown
  
    /* destroy the timer only if intialized */
    if (pWdContext->thread_stuck_timer.state != VOS_TIMER_STATE_UNUSED) {
      vos_timer_destroy(&pWdContext->thread_stuck_timer);
    }
    // If we get here the Watchdog thread must exit
    VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
        "%s: Watchdog Thread exiting !!!!", __func__);
    complete_and_exit(&pWdContext->WdShutdown, 0);
  
  err_reset:
      VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
        "%s: Watchdog Thread Failed to Reset, Exiting!!!!", __func__);
      return 0;
  
  } /* VosMCThread() */
  
  #ifdef QCA_CONFIG_SMP
  /*---------------------------------------------------------------------------
    \brief vos_free_tlshim_pkt_freeq() - Free voss buffer free queue
    The \a vos_free_tlshim_pkt_freeq() does mem free of the buffers
    available in free vos buffer queue which is used for Data rx processing
    from Tlshim.
    \param pSchedContext - pointer to the global vOSS Sched Context
  
    \return Nothing
    \sa vos_free_tlshim_pkt_freeq()
    -------------------------------------------------------------------------*/
  void vos_free_tlshim_pkt_freeq(pVosSchedContext pSchedContext)
  {
     struct VosTlshimPkt *pkt;
  
     SPIN_LOCK_BH(&pSchedContext->VosTlshimPktFreeQLock);
     while (!list_empty(&pSchedContext->VosTlshimPktFreeQ)) {
         pkt = list_entry((&pSchedContext->VosTlshimPktFreeQ)->next,
                       typeof(*pkt), list);
         list_del(&pkt->list);
         SPIN_UNLOCK_BH(&pSchedContext->VosTlshimPktFreeQLock);
         vos_mem_free(pkt);
         SPIN_LOCK_BH(&pSchedContext->VosTlshimPktFreeQLock);
     }
     SPIN_UNLOCK_BH(&pSchedContext->VosTlshimPktFreeQLock);
  
  }
  
  /*---------------------------------------------------------------------------
    \brief vos_alloc_tlshim_pkt_freeq() - Function to allocate free buffer queue
    The \a vos_alloc_tlshim_pkt_freeq() allocates VOSS_MAX_TLSHIM_PKT
    number of vos message buffers which are used for Rx data processing
    from Tlshim.
    \param  pSchedContext - pointer to the global vOSS Sched Context
  
    \return status of memory allocation
    \sa vos_alloc_tlshim_pkt_freeq()
    -------------------------------------------------------------------------*/
  static VOS_STATUS vos_alloc_tlshim_pkt_freeq(pVosSchedContext pSchedContext)
  {
     struct VosTlshimPkt *pkt, *tmp;
     int i;
  
     for (i = 0; i < VOSS_MAX_TLSHIM_PKT; i++) {
         pkt = vos_mem_malloc(sizeof(*pkt));
         if (!pkt) {
             VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                        "%s Vos packet allocation for tlshim thread failed",
                        __func__);
             goto free;
         }
         memset(pkt, 0, sizeof(*pkt));
         list_add_tail(&pkt->list, &pSchedContext->VosTlshimPktFreeQ);
     }
  
     return VOS_STATUS_SUCCESS;
  
  free:
     list_for_each_entry_safe(pkt, tmp, &pSchedContext->VosTlshimPktFreeQ, list) {
         list_del(&pkt->list);
         vos_mem_free(pkt);
     }
     return VOS_STATUS_E_NOMEM;
  }
  
  /*---------------------------------------------------------------------------
    \brief vos_free_tlshim_pkt() - API to release vos message to the freeq
    The \a vos_free_tlshim_pkt() returns the vos message used for Rx data
    to the free queue.
    \param  pSchedContext - pointer to the global vOSS Sched Context
    \param  pkt - Vos message buffer to be returned to free queue.
  
    \return Nothing
    \sa vos_free_tlshim_pkt()
    -------------------------------------------------------------------------*/
  void vos_free_tlshim_pkt(pVosSchedContext pSchedContext,
                           struct VosTlshimPkt *pkt)
  {
     memset(pkt, 0, sizeof(*pkt));
     SPIN_LOCK_BH(&pSchedContext->VosTlshimPktFreeQLock);
     list_add_tail(&pkt->list, &pSchedContext->VosTlshimPktFreeQ);
     SPIN_UNLOCK_BH(&pSchedContext->VosTlshimPktFreeQLock);
  }
  
  /*---------------------------------------------------------------------------
    \brief vos_alloc_tlshim_pkt() - API to return next available vos message
    The \a vos_alloc_tlshim_pkt() returns next available vos message buffer
    used for Rx Data processing.
    \param pSchedContext - pointer to the global vOSS Sched Context
  
    \return pointer to vos message buffer
    \sa vos_alloc_tlshim_pkt()
    -------------------------------------------------------------------------*/
  struct VosTlshimPkt *vos_alloc_tlshim_pkt(pVosSchedContext pSchedContext)
  {
     struct VosTlshimPkt *pkt;
  
     SPIN_LOCK_BH(&pSchedContext->VosTlshimPktFreeQLock);
     if (list_empty(&pSchedContext->VosTlshimPktFreeQ)) {
         SPIN_UNLOCK_BH(&pSchedContext->VosTlshimPktFreeQLock);
         return NULL;
     }
     pkt = list_first_entry(&pSchedContext->VosTlshimPktFreeQ,
                            struct VosTlshimPkt, list);
     list_del(&pkt->list);
     SPIN_UNLOCK_BH(&pSchedContext->VosTlshimPktFreeQLock);
     return pkt;
  }
  
  /*---------------------------------------------------------------------------
    \brief vos_indicate_rxpkt() - API to Indicate rx data packet
    The \a vos_indicate_rxpkt() enqueues the rx packet onto tlshimRxQueue
    and notifies VosTlshimRxThread().
    \param  Arg - pointer to the global vOSS Sched Context
    \param pkt - Vos data message buffer
  
    \return Nothing
    \sa vos_indicate_rxpkt()
    -------------------------------------------------------------------------*/
  void vos_indicate_rxpkt(pVosSchedContext pSchedContext,
                          struct VosTlshimPkt *pkt)
  {
     SPIN_LOCK_BH(&pSchedContext->TlshimRxQLock);
     list_add_tail(&pkt->list, &pSchedContext->tlshimRxQueue);
     SPIN_UNLOCK_BH(&pSchedContext->TlshimRxQLock);
     set_bit(RX_POST_EVENT, &pSchedContext->tlshimRxEvtFlg);
     wake_up_interruptible(&pSchedContext->tlshimRxWaitQueue);
  }
  
  /*---------------------------------------------------------------------------
    \brief vos_drop_rxpkt_by_staid() - API to drop pending Rx packets for a sta
    The \a vos_drop_rxpkt_by_staid() drops queued packets for a station, to drop
    all the pending packets the caller has to send WLAN_MAX_STA_COUNT as staId.
    \param  pSchedContext - pointer to the global vOSS Sched Context
    \param staId - Station Id
  
    \return Nothing
    \sa vos_drop_rxpkt_by_staid()
    -------------------------------------------------------------------------*/
  void vos_drop_rxpkt_by_staid(pVosSchedContext pSchedContext, u_int16_t staId)
  {
     struct list_head local_list;
     struct VosTlshimPkt *pkt, *tmp;
     adf_nbuf_t buf, next_buf;
  
     INIT_LIST_HEAD(&local_list);
     SPIN_LOCK_BH(&pSchedContext->TlshimRxQLock);
     if (list_empty(&pSchedContext->tlshimRxQueue)) {
         SPIN_UNLOCK_BH(&pSchedContext->TlshimRxQLock);
         return;
     }
     list_for_each_entry_safe(pkt, tmp, &pSchedContext->tlshimRxQueue, list) {
         if (pkt->staId == staId || staId == WLAN_MAX_STA_COUNT)
             list_move_tail(&pkt->list, &local_list);
     }
     SPIN_UNLOCK_BH(&pSchedContext->TlshimRxQLock);
  
     list_for_each_entry_safe(pkt, tmp, &local_list, list) {
         list_del(&pkt->list);
         buf = pkt->Rxpkt;
         while (buf) {
             next_buf = adf_nbuf_queue_next(buf);
             adf_nbuf_free(buf);
             buf = next_buf;
         }
         vos_free_tlshim_pkt(pSchedContext, pkt);
     }
  }
  
  /*---------------------------------------------------------------------------
    \brief vos_rx_from_queue() - Function to process pending Rx packets
    The \a vos_rx_from_queue() traverses the pending buffer list and calling
    the callback. This callback would essentially send the packet to HDD.
    \param  pSchedContext - pointer to the global vOSS Sched Context
  
    \return Nothing
    \sa vos_rx_from_queue()
    -------------------------------------------------------------------------*/
  static void vos_rx_from_queue(pVosSchedContext pSchedContext)
  {
     struct VosTlshimPkt *pkt;
     u_int16_t sta_id;
  
     SPIN_LOCK_BH(&pSchedContext->TlshimRxQLock);
     while (!list_empty(&pSchedContext->tlshimRxQueue)) {
             pkt = list_first_entry(&pSchedContext->tlshimRxQueue,
                                    struct VosTlshimPkt, list);
             list_del(&pkt->list);
             SPIN_UNLOCK_BH(&pSchedContext->TlshimRxQLock);
             sta_id = pkt->staId;
             pkt->callback(pkt->context, pkt->Rxpkt, sta_id);
             vos_free_tlshim_pkt(pSchedContext, pkt);
             SPIN_LOCK_BH(&pSchedContext->TlshimRxQLock);
     }
     SPIN_UNLOCK_BH(&pSchedContext->TlshimRxQLock);
  }
  
  /*---------------------------------------------------------------------------
    \brief VosTlshimRxThread() - The VOSS Main Tlshim Rx thread
    The \a VosTlshimRxThread() is the thread for Tlshim Data packet processing.
    \param  Arg - pointer to the global vOSS Sched Context
  
    \return Thread exit code
    \sa VosTlshimRxThread()
    -------------------------------------------------------------------------*/
  static int VosTlshimRxThread(void *arg)
  {
     pVosSchedContext pSchedContext = (pVosSchedContext)arg;
     unsigned long pref_cpu = 0;
     bool shutdown = false;
     int status, i;
  
     set_user_nice(current, -1);
  #ifdef MSM_PLATFORM
     set_wake_up_idle(true);
  #endif
  
     /* Find the available cpu core other than cpu 0 and
      * bind the thread */
     for_each_online_cpu(i) {
         if (i == 0)
             continue;
         pref_cpu = i;
             break;
     }
     if (pref_cpu != 0 && (!vos_set_cpus_allowed_ptr(current, pref_cpu)))
         affine_cpu = pref_cpu;
  
     if (!arg) {
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
         "%s: Bad Args passed", __func__);
         return 0;
     }
  
     complete(&pSchedContext->TlshimRxStartEvent);
  
     while (!shutdown) {
         status = wait_event_interruptible(pSchedContext->tlshimRxWaitQueue,
                           test_bit(RX_POST_EVENT,
                                    &pSchedContext->tlshimRxEvtFlg) ||
                           test_bit(RX_SUSPEND_EVENT,
                                    &pSchedContext->tlshimRxEvtFlg));
         if (status == -ERESTARTSYS)
             break;
  
         clear_bit(RX_POST_EVENT, &pSchedContext->tlshimRxEvtFlg);
         while (true) {
             if (test_bit(RX_SHUTDOWN_EVENT,
                        &pSchedContext->tlshimRxEvtFlg)) {
                 clear_bit(RX_SHUTDOWN_EVENT,
                           &pSchedContext->tlshimRxEvtFlg);
                 if (test_bit(RX_SUSPEND_EVENT,
                              &pSchedContext->tlshimRxEvtFlg)) {
                     clear_bit(RX_SUSPEND_EVENT,
                               &pSchedContext->tlshimRxEvtFlg);
                     complete(&pSchedContext->SuspndTlshimRxEvent);
                 }
                 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                           "%s: Shutting down tl shim Tlshim rx thread", __func__);
                 shutdown = true;
                 break;
             }
             vos_rx_from_queue(pSchedContext);
  
             if (test_bit(RX_SUSPEND_EVENT,
                          &pSchedContext->tlshimRxEvtFlg)) {
                 clear_bit(RX_SUSPEND_EVENT,
                           &pSchedContext->tlshimRxEvtFlg);
                 spin_lock(&pSchedContext->TlshimRxThreadLock);
                 INIT_COMPLETION(pSchedContext->ResumeTlshimRxEvent);
                 complete(&pSchedContext->SuspndTlshimRxEvent);
                 spin_unlock(&pSchedContext->TlshimRxThreadLock);
                 wait_for_completion_interruptible(
                                &pSchedContext->ResumeTlshimRxEvent);
             }
             break;
         }
     }
  
     VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
               "%s: Exiting VOSS Tlshim rx thread", __func__);
     complete_and_exit(&pSchedContext->TlshimRxShutdown, 0);
  }
  #endif
  
  /*---------------------------------------------------------------------------
    \brief vos_sched_close() - Close the vOSS Scheduler
    The \a vos_sched_closes() function closes the vOSS Scheduler
    Upon successful closing:
       - All the message queues are flushed
       - The Main Controller thread is closed
       - The Tx thread is closed
  
    \param  pVosContext - pointer to the global vOSS Context
    \return VOS_STATUS_SUCCESS - Scheduler was successfully initialized and
            is ready to be used.
            VOS_STATUS_E_INVAL - Invalid parameter passed to the scheduler Open
            function
            VOS_STATUS_E_FAILURE - Failure to initialize the scheduler/
    \sa vos_sched_close()
  ---------------------------------------------------------------------------*/
  VOS_STATUS vos_sched_close ( v_PVOID_t pVosContext )
  {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
          "%s: invoked", __func__);
      if (gpVosSchedContext == NULL)
      {
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
             "%s: gpVosSchedContext == NULL",__func__);
         return VOS_STATUS_E_FAILURE;
      }
  
      // shut down MC Thread
      set_bit(MC_SHUTDOWN_EVENT, &gpVosSchedContext->mcEventFlag);
      set_bit(MC_POST_EVENT, &gpVosSchedContext->mcEventFlag);
      wake_up_interruptible(&gpVosSchedContext->mcWaitQueue);
      //Wait for MC to exit
      wait_for_completion(&gpVosSchedContext->McShutdown);
      gpVosSchedContext->McThread = 0;
  
      //Clean up message queues of MC thread
      vos_sched_flush_mc_mqs(gpVosSchedContext);
  
      //Deinit all the queues
      vos_sched_deinit_mqs(gpVosSchedContext);
  
  #ifdef QCA_CONFIG_SMP
      vos_lock_destroy(&gpVosSchedContext->affinity_lock);
      // Shut down Tlshim Rx thread
      set_bit(RX_SHUTDOWN_EVENT, &gpVosSchedContext->tlshimRxEvtFlg);
      set_bit(RX_POST_EVENT, &gpVosSchedContext->tlshimRxEvtFlg);
      wake_up_interruptible(&gpVosSchedContext->tlshimRxWaitQueue);
      wait_for_completion(&gpVosSchedContext->TlshimRxShutdown);
      gpVosSchedContext->TlshimRxThread = NULL;
      vos_drop_rxpkt_by_staid(gpVosSchedContext, WLAN_MAX_STA_COUNT);
      vos_free_tlshim_pkt_freeq(gpVosSchedContext);
      //unregister_hotcpu_notifier(&vos_cpu_hotplug_notifier);
  #endif
      return VOS_STATUS_SUCCESS;
  } /* vox_sched_close() */
  
  VOS_STATUS vos_watchdog_close ( v_PVOID_t pVosContext )
  {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
          "%s: vos_watchdog closing now", __func__);
      if (gpVosWatchdogContext == NULL)
      {
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
             "%s: gpVosWatchdogContext is NULL",__func__);
         return VOS_STATUS_E_FAILURE;
      }
      set_bit(WD_SHUTDOWN_EVENT, &gpVosWatchdogContext->wdEventFlag);
      set_bit(WD_POST_EVENT, &gpVosWatchdogContext->wdEventFlag);
      wake_up_interruptible(&gpVosWatchdogContext->wdWaitQueue);
      //Wait for Watchdog thread to exit
      wait_for_completion(&gpVosWatchdogContext->WdShutdown);
      return VOS_STATUS_SUCCESS;
  } /* vos_watchdog_close() */
  
  /*---------------------------------------------------------------------------
    \brief vos_sched_init_mqs: Initialize the vOSS Scheduler message queues
    The \a vos_sched_init_mqs() function initializes the vOSS Scheduler
    message queues.
    \param  pVosSchedContext - pointer to the Scheduler Context.
    \return VOS_STATUS_SUCCESS - Scheduler was successfully initialized and
            is ready to be used.
            VOS_STATUS_E_RESOURCES - System resources (other than memory)
            are unavailable to initilize the scheduler
  
    \sa vos_sched_init_mqs()
    -------------------------------------------------------------------------*/
  VOS_STATUS vos_sched_init_mqs ( pVosSchedContext pSchedContext )
  {
    VOS_STATUS vStatus = VOS_STATUS_SUCCESS;
    // Now intialize all the message queues
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
              "%s: Initializing the WDA MC Message queue",__func__);
    vStatus = vos_mq_init(&pSchedContext->wdaMcMq);
    if (! VOS_IS_STATUS_SUCCESS(vStatus))
    {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
              "%s: Failed to init WDA MC Message queue",__func__);
      VOS_ASSERT(0);
      return vStatus;
    }
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
              "%s: Initializing the PE MC Message queue",__func__);
    vStatus = vos_mq_init(&pSchedContext->peMcMq);
    if (! VOS_IS_STATUS_SUCCESS(vStatus))
    {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
              "%s: Failed to init PE MC Message queue",__func__);
      VOS_ASSERT(0);
      return vStatus;
    }
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
              "%s: Initializing the SME MC Message queue", __func__);
    vStatus = vos_mq_init(&pSchedContext->smeMcMq);
    if (! VOS_IS_STATUS_SUCCESS(vStatus))
    {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
              "%s: Failed to init SME MC Message queue",__func__);
      VOS_ASSERT(0);
      return vStatus;
    }
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
              "%s: Initializing the TL MC Message queue",__func__);
    vStatus = vos_mq_init(&pSchedContext->tlMcMq);
    if (! VOS_IS_STATUS_SUCCESS(vStatus))
    {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
              "%s: Failed to init TL MC Message queue",__func__);
      VOS_ASSERT(0);
      return vStatus;
    }
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
              "%s: Initializing the SYS MC Message queue",__func__);
    vStatus = vos_mq_init(&pSchedContext->sysMcMq);
    if (! VOS_IS_STATUS_SUCCESS(vStatus))
    {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
              "%s: Failed to init SYS MC Message queue",__func__);
      VOS_ASSERT(0);
      return vStatus;
    }
  
    return VOS_STATUS_SUCCESS;
  } /* vos_sched_init_mqs() */
  
  /*---------------------------------------------------------------------------
    \brief vos_sched_deinit_mqs: Deinitialize the vOSS Scheduler message queues
    The \a vos_sched_init_mqs() function deinitializes the vOSS Scheduler
    message queues.
    \param  pVosSchedContext - pointer to the Scheduler Context.
    \return None
    \sa vos_sched_deinit_mqs()
    -------------------------------------------------------------------------*/
  void vos_sched_deinit_mqs ( pVosSchedContext pSchedContext )
  {
    // Now de-intialize all message queues
   // MC WDA
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
              "%s De-Initializing the WDA MC Message queue",__func__);
    vos_mq_deinit(&pSchedContext->wdaMcMq);
    //MC PE
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
              "%s De-Initializing the PE MC Message queue",__func__);
    vos_mq_deinit(&pSchedContext->peMcMq);
    //MC SME
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
              "%s De-Initializing the SME MC Message queue",__func__);
    vos_mq_deinit(&pSchedContext->smeMcMq);
    //MC TL
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
              "%s De-Initializing the TL MC Message queue",__func__);
    vos_mq_deinit(&pSchedContext->tlMcMq);
    //MC SYS
    VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
              "%s De-Initializing the SYS MC Message queue",__func__);
    vos_mq_deinit(&pSchedContext->sysMcMq);
  
  } /* vos_sched_deinit_mqs() */
  
  /*-------------------------------------------------------------------------
   this helper function flushes all the MC message queues
   -------------------------------------------------------------------------*/
  void vos_sched_flush_mc_mqs ( pVosSchedContext pSchedContext )
  {
    pVosMsgWrapper pMsgWrapper = NULL;
    pVosContextType vosCtx;
  
    /*
    ** Here each of the MC thread MQ shall be drained and returned to the
    ** Core. Before returning a wrapper to the Core, the VOS message shall be
    ** freed  first
    */
    VOS_TRACE( VOS_MODULE_ID_VOSS,
               VOS_TRACE_LEVEL_INFO,
               ("Flushing the MC Thread message queue") );
  
    if (NULL == pSchedContext)
    {
       VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
           "%s: pSchedContext is NULL", __func__);
       return;
    }
  
    vosCtx = (pVosContextType)(pSchedContext->pVContext);
    if (NULL == vosCtx)
    {
       VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                  "%s: vosCtx is NULL", __func__);
       return;
    }
  
    /* Flush the SYS Mq */
    while( NULL != (pMsgWrapper = vos_mq_get(&pSchedContext->sysMcMq) ))
    {
      VOS_TRACE( VOS_MODULE_ID_VOSS,
                 VOS_TRACE_LEVEL_INFO,
                 "%s: Freeing MC SYS message type %d ",__func__,
                 pMsgWrapper->pVosMsg->type );
      sysMcFreeMsg(pSchedContext->pVContext, pMsgWrapper->pVosMsg);
      vos_core_return_msg(pSchedContext->pVContext, pMsgWrapper);
    }
    /* Flush the WDA Mq */
    while( NULL != (pMsgWrapper = vos_mq_get(&pSchedContext->wdaMcMq) ))
    {
      if(pMsgWrapper->pVosMsg != NULL)
      {
          VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
                     "%s: Freeing MC WDA MSG message type %d",
                     __func__, pMsgWrapper->pVosMsg->type );
          if (pMsgWrapper->pVosMsg->bodyptr) {
              vos_mem_free((v_VOID_t*)pMsgWrapper->pVosMsg->bodyptr);
          }
  
          pMsgWrapper->pVosMsg->bodyptr = NULL;
          pMsgWrapper->pVosMsg->bodyval = 0;
          pMsgWrapper->pVosMsg->type = 0;
      }
      vos_core_return_msg(pSchedContext->pVContext, pMsgWrapper);
    }
  
    /* Flush the PE Mq */
    while( NULL != (pMsgWrapper = vos_mq_get(&pSchedContext->peMcMq) ))
    {
      VOS_TRACE( VOS_MODULE_ID_VOSS,
                 VOS_TRACE_LEVEL_INFO,
                 "%s: Freeing MC PE MSG message type %d",__func__,
                 pMsgWrapper->pVosMsg->type );
      peFreeMsg(vosCtx->pMACContext, (tSirMsgQ*)pMsgWrapper->pVosMsg);
      vos_core_return_msg(pSchedContext->pVContext, pMsgWrapper);
    }
    /* Flush the SME Mq */
    while( NULL != (pMsgWrapper = vos_mq_get(&pSchedContext->smeMcMq) ))
    {
      VOS_TRACE( VOS_MODULE_ID_VOSS,
                 VOS_TRACE_LEVEL_INFO,
                 "%s: Freeing MC SME MSG message type %d", __func__,
                 pMsgWrapper->pVosMsg->type );
      sme_FreeMsg(vosCtx->pMACContext, pMsgWrapper->pVosMsg);
      vos_core_return_msg(pSchedContext->pVContext, pMsgWrapper);
    }
      /* Flush the TL Mq */
    while( NULL != (pMsgWrapper = vos_mq_get(&pSchedContext->tlMcMq) ))
    {
      VOS_TRACE( VOS_MODULE_ID_VOSS,
                 VOS_TRACE_LEVEL_INFO,
                 "%s: Freeing MC TL message type %d",__func__,
                 pMsgWrapper->pVosMsg->type );
      WLANTL_McFreeMsg(pSchedContext->pVContext, pMsgWrapper->pVosMsg);
      vos_core_return_msg(pSchedContext->pVContext, pMsgWrapper);
    }
  } /* vos_sched_flush_mc_mqs() */
  
  /*-------------------------------------------------------------------------
   Helper function to get the scheduler context
   ------------------------------------------------------------------------*/
  pVosSchedContext get_vos_sched_ctxt(void)
  {
     //Make sure that Vos Scheduler context has been initialized
     if (gpVosSchedContext == NULL)
     {
        VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
           "%s: gpVosSchedContext == NULL",__func__);
     }
     return (gpVosSchedContext);
  }
  
  
  /**
   * vos_is_mc_thread()- Check if threadid is
   * of mc thread
   *
   * @thread_id: passed threadid
   * This function is called to check if threadid is
   * of mc thread.
   *
   * Return: true if threadid is of mc thread.
   */
  int vos_sched_is_mc_thread(int thread_id)
  {
  	/* Make sure that Vos Scheduler context has been initialized */
  	VOS_ASSERT(NULL != gpVosSchedContext);
  	if (gpVosSchedContext == NULL) {
  		VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
  				"%s: gpVosSchedContext == NULL", __func__);
  		return 0;
  	}
  	return ((gpVosSchedContext->McThread) &&
  			(thread_id ==
  			 gpVosSchedContext->McThread->pid));
  }
  
  /*-------------------------------------------------------------------------
   Helper function to get the watchdog context
   ------------------------------------------------------------------------*/
  pVosWatchdogContext get_vos_watchdog_ctxt(void)
  {
     //Make sure that Vos Scheduler context has been initialized
     if (gpVosWatchdogContext == NULL)
     {
        VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
           "%s: gpVosWatchdogContext == NULL",__func__);
     }
     return (gpVosWatchdogContext);
  }
  /**
    @brief vos_watchdog_wlan_shutdown()
  
    This function is called to shutdown WLAN driver during SSR.
    Adapters are disabled, and the watchdog task will be signalled
    to shutdown WLAN driver.
  
    @param
           NONE
    @return
           VOS_STATUS_SUCCESS   - Operation completed successfully.
           VOS_STATUS_E_FAILURE - Operation failed.
  
  */
  VOS_STATUS vos_watchdog_wlan_shutdown(void)
  {
      v_CONTEXT_t pVosContext = NULL;
      hdd_context_t *pHddCtx = NULL;
  
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
          "%s: WLAN driver is shutting down ", __func__);
      if (NULL == gpVosWatchdogContext)
      {
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
             "%s: Watchdog not enabled. LOGP ignored.", __func__);
         return VOS_STATUS_E_FAILURE;
      }
  
      pVosContext = vos_get_global_context(VOS_MODULE_ID_HDD, NULL);
      pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext );
      if (NULL == pHddCtx)
      {
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
             "%s: Invalid HDD Context", __func__);
         return VOS_STATUS_E_FAILURE;
      }
  
      /* Take the lock here */
      spin_lock(&gpVosWatchdogContext->wdLock);
  
      /* reuse the existing 'reset in progress' */
      if (gpVosWatchdogContext->resetInProgress)
      {
          VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
              "%s: Shutdown already in Progress. Ignoring signaling Watchdog",
                                                             __func__);
          /* Release the lock here */
          spin_unlock(&gpVosWatchdogContext->wdLock);
          return VOS_STATUS_E_FAILURE;
      }
      /* reuse the existing 'logp in progress', eventhough it is not
       * exactly the same */
      else if (pHddCtx->isLogpInProgress)
      {
          VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
              "%s: shutdown/re-init already in Progress. Ignoring signaling Watchdog",
                                                             __func__);
          /* Release the lock here */
          spin_unlock(&gpVosWatchdogContext->wdLock);
          return VOS_STATUS_E_FAILURE;
      }
  
      /* Set the flags so that all future CMD53 and Wext commands get blocked right away */
      vos_set_logp_in_progress(VOS_MODULE_ID_VOSS, TRUE);
      vos_set_reinit_in_progress(VOS_MODULE_ID_VOSS, FALSE);
      pHddCtx->isLogpInProgress = TRUE;
  
      /* Release the lock here */
      spin_unlock(&gpVosWatchdogContext->wdLock);
  
      if ((pHddCtx->isLoadInProgress) ||
          (pHddCtx->isUnloadInProgress))
      {
          VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
                  "%s: Load/unload in Progress. Ignoring signaling Watchdog",
                  __func__);
          /* wcnss has crashed, and SSR has alredy been started by Kernel driver.
           * So disable SSR from WLAN driver */
          hdd_set_ssr_required( HDD_SSR_DISABLED );
          return VOS_STATUS_E_FAILURE;
      }
      /* Update Riva Reset Statistics */
      pHddCtx->hddRivaResetStats++;
  #ifdef CONFIG_HAS_EARLYSUSPEND
      if(VOS_STATUS_SUCCESS != hdd_wlan_reset_initialization())
      {
         VOS_ASSERT(0);
      }
  #endif
  
      set_bit(WD_WLAN_SHUTDOWN_EVENT, &gpVosWatchdogContext->wdEventFlag);
      set_bit(WD_POST_EVENT, &gpVosWatchdogContext->wdEventFlag);
      wake_up_interruptible(&gpVosWatchdogContext->wdWaitQueue);
  
      return VOS_STATUS_SUCCESS;
  }
  
  /**
    @brief vos_watchdog_wlan_re_init()
  
    This function is called to re-initialize WLAN driver, and this is
    called when Riva SS reboots.
  
    @param
           NONE
    @return
           VOS_STATUS_SUCCESS   - Operation completed successfully.
           VOS_STATUS_E_FAILURE - Operation failed.
  
  */
  VOS_STATUS vos_watchdog_wlan_re_init(void)
  {
      /* Make sure that Vos Watchdog context has been initialized */
      if (gpVosWatchdogContext == NULL) {
          VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
              "%s: gpVosWatchdogContext == NULL", __func__);
          return VOS_STATUS_SUCCESS;
      }
      /* watchdog task is still running, it is not closed in shutdown */
      set_bit(WD_WLAN_REINIT_EVENT, &gpVosWatchdogContext->wdEventFlag);
      set_bit(WD_POST_EVENT, &gpVosWatchdogContext->wdEventFlag);
      wake_up_interruptible(&gpVosWatchdogContext->wdWaitQueue);
  
      return VOS_STATUS_SUCCESS;
  }
  
  /**
   * vos_ssr_protect_init() - initialize ssr protection debug functionality
   *
   * Return:
   *        void
   */
  void vos_ssr_protect_init(void)
  {
      int i = 0;
  
      spin_lock_init(&ssr_protect_lock);
  
      while (i < MAX_SSR_PROTECT_LOG) {
         ssr_protect_log[i].func = NULL;
         ssr_protect_log[i].free = true;
         ssr_protect_log[i].pid =  0;
         i++;
      }
  }
  
  /**
   * vos_print_external_threads() - print external threads stuck in driver
   *
   * Return:
   *        void
   */
  
  static void vos_print_external_threads(void)
  {
      int i = 0;
      unsigned long irq_flags;
  
      spin_lock_irqsave(&ssr_protect_lock, irq_flags);
  
      while (i < MAX_SSR_PROTECT_LOG) {
          if (!ssr_protect_log[i].free) {
              VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
                 "PID %d is stuck at %s", ssr_protect_log[i].pid,
                 ssr_protect_log[i].func);
          }
          i++;
      }
  
      spin_unlock_irqrestore(&ssr_protect_lock, irq_flags);
  }
  
  
  /**
   * vos_is_load_unload_ready() - check load/unload ready
   * @caller_func: Pointer to caller function
   *
   * This function will check if calling execution can call
   * kickstart driver for load/unload
   *
   * Return: true if ready else false.
   */
  bool vos_is_load_unload_ready(const char *caller_func)
  {
  	int count = MAX_LOAD_UNLOAD_WAIT_ITERATIONS;
  
  	while (count) {
  		if (!atomic_read(&load_unload_protect_count))
  			break;
  
  		if (--count) {
  			VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
  				"%s: Waiting for load/unload active entry points to exit",
  				__func__);
  			msleep(LOAD_UNLOAD_WAIT_SLEEP_TIME);
  		}
  	}
  	/* at least one external thread is executing */
  	if (!count) {
  		VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
  			"%s : Thread stuck for load/unload", __func__);
  		return false;
  	}
  
  	VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
  		"Allowing load/Unload for %s", caller_func);
  
  	return true;
  }
  
  
  /**
   * vos_load_unload_protect () - Protect load/Unload
   * @caller_func : Pointer to caller function
   *
   * This function will protect the atomic variable by incrementing
   * its value
   *
   * Return: void
   */
  
  void vos_load_unload_protect(const char *caller_func)
  {
  	atomic_inc(&load_unload_protect_count);
  }
  
  /**
   * vos_load_unload_unprotect () - Unprotect load/unload
   * @caller_func : Pointer to caller_func
   *
   * This function will decrement the atomic variable value
   *
   * Return: void
   */
  void vos_load_unload_unprotect(const char *caller_func)
  {
  	atomic_dec(&load_unload_protect_count);
  }
  
  /**
    @brief vos_ssr_protect()
  
    This function is called to keep track of active driver entry points
  
    @param
           caller_func - Name of calling function.
    @return
           void
  */
  void vos_ssr_protect(const char *caller_func)
  {
       int count;
       int i = 0;
       bool status = false;
       unsigned long irq_flags;
  
       count = atomic_inc_return(&ssr_protect_entry_count);
  
       spin_lock_irqsave(&ssr_protect_lock, irq_flags);
  
       while (i < MAX_SSR_PROTECT_LOG) {
           if (ssr_protect_log[i].free) {
                ssr_protect_log[i].func = caller_func;
                ssr_protect_log[i].free = false;
                ssr_protect_log[i].pid = current->pid;
                status = true;
                break;
           }
           i++;
       }
  
       spin_unlock_irqrestore(&ssr_protect_lock, irq_flags);
  
       if (!status)
           VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
               "Could not track PID %d call %s: log is full",
               current->pid, caller_func);
  
  }
  
  /**
    @brief vos_ssr_unprotect()
  
    @param
           caller_func - Name of calling function.
    @return
           void
  */
  void vos_ssr_unprotect(const char *caller_func)
  {
     int count;
     int i = 0;
     bool status = false;
     unsigned long irq_flags;
  
     count = atomic_dec_return(&ssr_protect_entry_count);
  
     spin_lock_irqsave(&ssr_protect_lock, irq_flags);
  
     while (i < MAX_SSR_PROTECT_LOG) {
        if (!ssr_protect_log[i].free) {
            if ((ssr_protect_log[i].pid == current->pid) &&
                !strcmp(ssr_protect_log[i].func, caller_func)) {
                ssr_protect_log[i].func = NULL;
                ssr_protect_log[i].free = true;
                ssr_protect_log[i].pid =  0;
                status = true;
                break;
            }
        }
        i++;
     }
  
     spin_unlock_irqrestore(&ssr_protect_lock, irq_flags);
  
     if (!status)
         VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
             "Untracked call %s", caller_func);
  }
  
  /**
   * vos_is_wd_thread()- Check if threadid is
   * of Watchdog thread
   *
   * @thread_id: passed threadid
   * This function is called to check if threadid is
   * of wd thread.
   *
   * Return: true if threadid is of wd thread.
   */
  bool vos_is_wd_thread(int thread_id)
  {
  	/*
  	 * Make sure that Vos Watchdong Scheduler context
  	 * has been initialized
  	 */
  	if (NULL == gpVosWatchdogContext)
  		return 0;
  
  	return ((gpVosWatchdogContext->WdThread) &&
  			(thread_id == gpVosWatchdogContext->WdThread->pid));
  }
  
  /**
    @brief vos_is_ssr_ready()
  
    This function will check if the calling execution can
    proceed with SSR.
  
    @param
           caller_func - Name of calling function.
    @return
           true or false
  */
  bool vos_is_ssr_ready(const char *caller_func)
  {
      int count = MAX_SSR_WAIT_ITERATIONS;
  
      while (count) {
  
          if (!atomic_read(&ssr_protect_entry_count))
              break;
  
          if (--count) {
              VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                      "%s: Waiting for active entry points to exit", __func__);
              msleep(SSR_WAIT_SLEEP_TIME);
          }
      }
      /* at least one external thread is executing */
      if (!count) {
          vos_print_external_threads();
          return false;
      }
  
     VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
               "Allowing SSR for %s", caller_func);
  
      return true;
  }
  
  /**
   * vos_get_gfp_flags(): get GFP flags
   *
   * Based on the scheduled context, return GFP flags
   * Return: gfp flags
   */
  int vos_get_gfp_flags(void)
  {
  	int flags = GFP_KERNEL;
  
  	if (in_interrupt() || in_atomic() || irqs_disabled())
  		flags = GFP_ATOMIC;
  
  	return flags;
  }
  