/*---------------------------------------------------------------------------- @brief Function to suspend the wlan driver. @param hdd_context_t pHddCtx Global hdd context @return None ----------------------------------------------------------------------------*/ static int wlan_suspend(hdd_context_t* pHddCtx) { int rc = 0; pVosSchedContext vosSchedContext = NULL; /* Get the global VOSS context */ vosSchedContext = get_vos_sched_ctxt(); if(!vosSchedContext) { VOS_TRACE(VOS_MODULE_ID_HDD,VOS_TRACE_LEVEL_FATAL,"%s: Global VOS_SCHED context is Null",__func__); return 0; } if(!vos_is_apps_power_collapse_allowed(pHddCtx)) { /* Fail this suspend */ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: Fail wlan suspend: not in IMPS/BMPS", __func__); return -1; } /* Suspending MC Thread, Rx Thread and Tx Thread as the platform driver is going to Suspend. */ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Suspending Mc, Rx and Tx Threads",__func__); init_completion(&pHddCtx->tx_sus_event_var); /* Indicate Tx Thread to Suspend */ set_bit(TX_SUSPEND_EVENT_MASK, &vosSchedContext->txEventFlag); wake_up_interruptible(&vosSchedContext->txWaitQueue); /* Wait for Suspend Confirmation from Tx Thread */ rc = wait_for_completion_interruptible_timeout(&pHddCtx->tx_sus_event_var, msecs_to_jiffies(200)); if(!rc) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: Not able to suspend TX thread timeout happened", __func__); clear_bit(TX_SUSPEND_EVENT_MASK, &vosSchedContext->txEventFlag); return -1; } /* Set the Tx Thread as Suspended */ pHddCtx->isTxThreadSuspended = TRUE; init_completion(&pHddCtx->rx_sus_event_var); /* Indicate Rx Thread to Suspend */ set_bit(RX_SUSPEND_EVENT_MASK, &vosSchedContext->rxEventFlag); wake_up_interruptible(&vosSchedContext->rxWaitQueue); /* Wait for Suspend Confirmation from Rx Thread */ rc = wait_for_completion_interruptible_timeout(&pHddCtx->rx_sus_event_var, msecs_to_jiffies(200)); if(!rc) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: Not able to suspend Rx thread timeout happened", __func__); clear_bit(RX_SUSPEND_EVENT_MASK, &vosSchedContext->rxEventFlag); /* Indicate Tx Thread to Resume */ complete(&vosSchedContext->ResumeTxEvent); /* Set the Tx Thread as Resumed */ pHddCtx->isTxThreadSuspended = FALSE; return -1; } /* Set the Rx Thread as Suspended */ pHddCtx->isRxThreadSuspended = TRUE; init_completion(&pHddCtx->mc_sus_event_var); /* Indicate MC Thread to Suspend */ set_bit(MC_SUSPEND_EVENT_MASK, &vosSchedContext->mcEventFlag); wake_up_interruptible(&vosSchedContext->mcWaitQueue); /* Wait for Suspend Confirmation from MC Thread */ rc = wait_for_completion_interruptible_timeout(&pHddCtx->mc_sus_event_var, msecs_to_jiffies(200)); if(!rc) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: Not able to suspend MC thread timeout happened", __func__); clear_bit(MC_SUSPEND_EVENT_MASK, &vosSchedContext->mcEventFlag); /* Indicate Rx Thread to Resume */ complete(&vosSchedContext->ResumeRxEvent); /* Set the Rx Thread as Resumed */ pHddCtx->isRxThreadSuspended = FALSE; /* Indicate Tx Thread to Resume */ complete(&vosSchedContext->ResumeTxEvent); /* Set the Tx Thread as Resumed */ pHddCtx->isTxThreadSuspended = FALSE; return -1; } /* Set the Mc Thread as Suspended */ pHddCtx->isMcThreadSuspended = TRUE; /* Set the Station state as Suspended */ pHddCtx->isWlanSuspended = TRUE; return 0; }
/*---------------------------------------------------------------------------- @brief Function to suspend the wlan driver. @param hdd_context_t pHddCtx Global hdd context @return None ----------------------------------------------------------------------------*/ static int wlan_suspend(hdd_context_t* pHddCtx) { long rc = 0; pVosSchedContext vosSchedContext = NULL; /* Get the global VOSS context */ vosSchedContext = get_vos_sched_ctxt(); if(!vosSchedContext) { VOS_TRACE(VOS_MODULE_ID_HDD,VOS_TRACE_LEVEL_FATAL,"%s: Global VOS_SCHED context is Null",__func__); return 0; } if(!vos_is_apps_power_collapse_allowed(pHddCtx)) { /* Fail this suspend */ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: Fail wlan suspend: not in IMPS/BMPS", __func__); return -EPERM; } /* Suspending MC Thread, Rx Thread and Tx Thread as the platform driver is going to Suspend. */ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Suspending Mc, Rx and Tx Threads",__func__); INIT_COMPLETION(pHddCtx->tx_sus_event_var); /* Indicate Tx Thread to Suspend */ set_bit(TX_SUSPEND_EVENT_MASK, &vosSchedContext->txEventFlag); wake_up_interruptible(&vosSchedContext->txWaitQueue); /* Wait for Suspend Confirmation from Tx Thread */ rc = wait_for_completion_interruptible_timeout(&pHddCtx->tx_sus_event_var, msecs_to_jiffies(200)); if (rc <= 0) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: TX Thread: timeout while suspending %ld" , __func__, rc); /* There is a race condition here, where the TX Thread can process the * SUSPEND_EVENT even after the wait_for_completion has timed out. * Check the SUSPEND_EVENT_MASK, if it is already cleared by the TX * Thread then it means it is going to suspend, so do not return failure * from here. */ if (!test_and_clear_bit(TX_SUSPEND_EVENT_MASK, &vosSchedContext->txEventFlag)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: TX Thread: will still suspend", __func__); goto tx_suspend; } return -ETIME; } tx_suspend: /* Set the Tx Thread as Suspended */ pHddCtx->isTxThreadSuspended = TRUE; INIT_COMPLETION(pHddCtx->rx_sus_event_var); /* Indicate Rx Thread to Suspend */ set_bit(RX_SUSPEND_EVENT_MASK, &vosSchedContext->rxEventFlag); wake_up_interruptible(&vosSchedContext->rxWaitQueue); /* Wait for Suspend Confirmation from Rx Thread */ rc = wait_for_completion_interruptible_timeout(&pHddCtx->rx_sus_event_var, msecs_to_jiffies(200)); if (rc <= 0) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: RX Thread: timeout while suspending %ld", __func__, rc); /* There is a race condition here, where the RX Thread can process the * SUSPEND_EVENT even after the wait_for_completion has timed out. * Check the SUSPEND_EVENT_MASK, if it is already cleared by the RX * Thread then it means it is going to suspend, so do not return failure * from here. */ if (!test_and_clear_bit(RX_SUSPEND_EVENT_MASK, &vosSchedContext->rxEventFlag)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: RX Thread: will still suspend", __func__); goto rx_suspend; } /* Indicate Tx Thread to Resume */ complete(&vosSchedContext->ResumeTxEvent); /* Set the Tx Thread as Resumed */ pHddCtx->isTxThreadSuspended = FALSE; return -ETIME; } rx_suspend: /* Set the Rx Thread as Suspended */ pHddCtx->isRxThreadSuspended = TRUE; INIT_COMPLETION(pHddCtx->mc_sus_event_var); /* Indicate MC Thread to Suspend */ set_bit(MC_SUSPEND_EVENT_MASK, &vosSchedContext->mcEventFlag); wake_up_interruptible(&vosSchedContext->mcWaitQueue); /* Wait for Suspend Confirmation from MC Thread */ rc = wait_for_completion_interruptible_timeout(&pHddCtx->mc_sus_event_var, msecs_to_jiffies(200)); if(!rc) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: MC Thread: timeout while suspending %ld", __func__, rc); /* There is a race condition here, where the MC Thread can process the * SUSPEND_EVENT even after the wait_for_completion has timed out. * Check the SUSPEND_EVENT_MASK, if it is already cleared by the MC * Thread then it means it is going to suspend, so do not return failure * from here. */ if (!test_and_clear_bit(MC_SUSPEND_EVENT_MASK, &vosSchedContext->mcEventFlag)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: MC Thread: will still suspend", __func__); goto mc_suspend; } /* Indicate Rx Thread to Resume */ complete(&vosSchedContext->ResumeRxEvent); /* Set the Rx Thread as Resumed */ pHddCtx->isRxThreadSuspended = FALSE; /* Indicate Tx Thread to Resume */ complete(&vosSchedContext->ResumeTxEvent); /* Set the Tx Thread as Resumed */ pHddCtx->isTxThreadSuspended = FALSE; return -ETIME; } mc_suspend: /* Set the Mc Thread as Suspended */ pHddCtx->isMcThreadSuspended = TRUE; /* Set the Station state as Suspended */ pHddCtx->isWlanSuspended = TRUE; return 0; }
static int wlan_suspend(hdd_context_t* pHddCtx) { long rc = 0; pVosSchedContext vosSchedContext = NULL; vosSchedContext = get_vos_sched_ctxt(); if(!vosSchedContext) { VOS_TRACE(VOS_MODULE_ID_HDD,VOS_TRACE_LEVEL_FATAL,"%s: Global VOS_SCHED context is Null",__func__); return 0; } if(!vos_is_apps_power_collapse_allowed(pHddCtx)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: Fail wlan suspend: not in IMPS/BMPS", __func__); return -EPERM; } VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Suspending Mc, Rx and Tx Threads",__func__); INIT_COMPLETION(pHddCtx->tx_sus_event_var); set_bit(TX_SUSPEND_EVENT_MASK, &vosSchedContext->txEventFlag); wake_up_interruptible(&vosSchedContext->txWaitQueue); rc = wait_for_completion_interruptible_timeout(&pHddCtx->tx_sus_event_var, msecs_to_jiffies(200)); if (rc <= 0) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: TX Thread: timeout while suspending %ld" , __func__, rc); if (!test_and_clear_bit(TX_SUSPEND_EVENT_MASK, &vosSchedContext->txEventFlag)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: TX Thread: will still suspend", __func__); goto tx_suspend; } return -ETIME; } tx_suspend: pHddCtx->isTxThreadSuspended = TRUE; INIT_COMPLETION(pHddCtx->rx_sus_event_var); set_bit(RX_SUSPEND_EVENT_MASK, &vosSchedContext->rxEventFlag); wake_up_interruptible(&vosSchedContext->rxWaitQueue); rc = wait_for_completion_interruptible_timeout(&pHddCtx->rx_sus_event_var, msecs_to_jiffies(200)); if (rc <= 0) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: RX Thread: timeout while suspending %ld", __func__, rc); if (!test_and_clear_bit(RX_SUSPEND_EVENT_MASK, &vosSchedContext->rxEventFlag)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: RX Thread: will still suspend", __func__); goto rx_suspend; } complete(&vosSchedContext->ResumeTxEvent); pHddCtx->isTxThreadSuspended = FALSE; return -ETIME; } rx_suspend: pHddCtx->isRxThreadSuspended = TRUE; INIT_COMPLETION(pHddCtx->mc_sus_event_var); set_bit(MC_SUSPEND_EVENT_MASK, &vosSchedContext->mcEventFlag); wake_up_interruptible(&vosSchedContext->mcWaitQueue); rc = wait_for_completion_interruptible_timeout(&pHddCtx->mc_sus_event_var, msecs_to_jiffies(200)); if(!rc) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: MC Thread: timeout while suspending %ld", __func__, rc); if (!test_and_clear_bit(MC_SUSPEND_EVENT_MASK, &vosSchedContext->mcEventFlag)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: MC Thread: will still suspend", __func__); goto mc_suspend; } complete(&vosSchedContext->ResumeRxEvent); pHddCtx->isRxThreadSuspended = FALSE; complete(&vosSchedContext->ResumeTxEvent); pHddCtx->isTxThreadSuspended = FALSE; return -ETIME; } mc_suspend: pHddCtx->isMcThreadSuspended = TRUE; pHddCtx->isWlanSuspended = TRUE; return 0; }