Files
wifi-rtl8852bs/core/rtw_pwrctrl.c
2024-03-01 19:54:35 +08:00

285 lines
8.3 KiB
C

/******************************************************************************
*
* Copyright(c) 2007 - 2021 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*****************************************************************************/
#define _RTW_PWRCTRL_C_
#include <drv_types.h>
#ifdef CONFIG_RTW_IPS
bool rtw_core_set_ips_state(void *drv_priv, enum rtw_rf_state state)
{
struct dvobj_priv *dvobj = (struct dvobj_priv *)drv_priv;
enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
if (state == RTW_RF_ON) {
pstatus = rtw_phl_rf_on(dvobj->phl);
} else if (state == RTW_RF_OFF) {
pstatus = rtw_phl_rf_off(dvobj->phl);
}
if (RTW_PHL_STATUS_SUCCESS == pstatus)
return true;
else
return false;
}
#endif
#ifdef CONFIG_RESUME_IN_WORKQUEUE
static void resume_workitem_callback(struct work_struct *work);
#endif /* CONFIG_RESUME_IN_WORKQUEUE */
void rtw_init_pwrctrl_priv(_adapter *padapter)
{
struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter);
#if defined(CONFIG_CONCURRENT_MODE)
if (!is_primary_adapter(padapter))
return;
#endif
pwrctrlpriv->bInSuspend = _FALSE;
pwrctrlpriv->bkeepfwalive = _FALSE;
#ifdef CONFIG_RESUME_IN_WORKQUEUE
_init_workitem(&pwrctrlpriv->resume_work, resume_workitem_callback, NULL);
pwrctrlpriv->rtw_workqueue = create_singlethread_workqueue("rtw_workqueue");
#endif /* CONFIG_RESUME_IN_WORKQUEUE */
}
void rtw_free_pwrctrl_priv(_adapter *adapter)
{
struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(adapter);
#if defined(CONFIG_CONCURRENT_MODE)
if (!is_primary_adapter(adapter))
return;
#endif
/* _rtw_memset((unsigned char *)pwrctrlpriv, 0, sizeof(struct pwrctrl_priv)); */
#ifdef CONFIG_RESUME_IN_WORKQUEUE
if (pwrctrlpriv->rtw_workqueue) {
flush_workqueue(pwrctrlpriv->rtw_workqueue);
destroy_workqueue(pwrctrlpriv->rtw_workqueue);
}
#endif
}
#ifdef CONFIG_RESUME_IN_WORKQUEUE
extern int rtw_resume_process(_adapter *padapter);
static void resume_workitem_callback(struct work_struct *work)
{
struct pwrctrl_priv *pwrpriv = container_of(work, struct pwrctrl_priv, resume_work);
struct dvobj_priv *dvobj = pwrctl_to_dvobj(pwrpriv);
_adapter *adapter = dvobj_get_primary_adapter(dvobj);
RTW_INFO("%s\n", __FUNCTION__);
rtw_resume_process(adapter);
rtw_resume_unlock_suspend();
}
void rtw_resume_in_workqueue(struct pwrctrl_priv *pwrpriv)
{
/* accquire system's suspend lock preventing from falliing asleep while resume in workqueue */
/* rtw_lock_suspend(); */
rtw_resume_lock_suspend();
#if 1
queue_work(pwrpriv->rtw_workqueue, &pwrpriv->resume_work);
#else
_set_workitem(&pwrpriv->resume_work);
#endif
}
#endif /* CONFIG_RESUME_IN_WORKQUEUE */
#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_ANDROID_POWER)
inline bool rtw_is_earlysuspend_registered(struct pwrctrl_priv *pwrpriv)
{
return (pwrpriv->early_suspend.suspend) ? _TRUE : _FALSE;
}
inline bool rtw_is_do_late_resume(struct pwrctrl_priv *pwrpriv)
{
return (pwrpriv->do_late_resume) ? _TRUE : _FALSE;
}
inline void rtw_set_do_late_resume(struct pwrctrl_priv *pwrpriv, bool enable)
{
pwrpriv->do_late_resume = enable;
}
#endif
#ifdef CONFIG_HAS_EARLYSUSPEND
extern int rtw_resume_process(_adapter *padapter);
static void rtw_early_suspend(struct early_suspend *h)
{
struct pwrctrl_priv *pwrpriv = container_of(h, struct pwrctrl_priv, early_suspend);
RTW_INFO("%s\n", __FUNCTION__);
rtw_set_do_late_resume(pwrpriv, _FALSE);
}
static void rtw_late_resume(struct early_suspend *h)
{
struct pwrctrl_priv *pwrpriv = container_of(h, struct pwrctrl_priv, early_suspend);
struct dvobj_priv *dvobj = pwrctl_to_dvobj(pwrpriv);
_adapter *adapter = dvobj_get_primary_adapter(dvobj);
RTW_INFO("%s\n", __FUNCTION__);
if (pwrpriv->do_late_resume) {
rtw_set_do_late_resume(pwrpriv, _FALSE);
rtw_resume_process(adapter);
}
}
void rtw_register_early_suspend(struct pwrctrl_priv *pwrpriv)
{
RTW_INFO("%s\n", __FUNCTION__);
/* jeff: set the early suspend level before blank screen, so we wll do late resume after scree is lit */
pwrpriv->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 20;
pwrpriv->early_suspend.suspend = rtw_early_suspend;
pwrpriv->early_suspend.resume = rtw_late_resume;
register_early_suspend(&pwrpriv->early_suspend);
}
void rtw_unregister_early_suspend(struct pwrctrl_priv *pwrpriv)
{
RTW_INFO("%s\n", __FUNCTION__);
rtw_set_do_late_resume(pwrpriv, _FALSE);
if (pwrpriv->early_suspend.suspend)
unregister_early_suspend(&pwrpriv->early_suspend);
pwrpriv->early_suspend.suspend = NULL;
pwrpriv->early_suspend.resume = NULL;
}
#endif /* CONFIG_HAS_EARLYSUSPEND */
#ifdef CONFIG_ANDROID_POWER
#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
extern int rtw_resume_process(_adapter *padapter);
#endif
static void rtw_early_suspend(android_early_suspend_t *h)
{
struct pwrctrl_priv *pwrpriv = container_of(h, struct pwrctrl_priv, early_suspend);
RTW_INFO("%s\n", __FUNCTION__);
rtw_set_do_late_resume(pwrpriv, _FALSE);
}
static void rtw_late_resume(android_early_suspend_t *h)
{
struct pwrctrl_priv *pwrpriv = container_of(h, struct pwrctrl_priv, early_suspend);
struct dvobj_priv *dvobj = pwrctl_to_dvobj(pwrpriv);
_adapter *adapter = dvobj_get_primary_adapter(dvobj);
RTW_INFO("%s\n", __FUNCTION__);
if (pwrpriv->do_late_resume) {
#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
rtw_set_do_late_resume(pwrpriv, _FALSE);
rtw_resume_process(adapter);
#endif
}
}
void rtw_register_early_suspend(struct pwrctrl_priv *pwrpriv)
{
RTW_INFO("%s\n", __FUNCTION__);
/* jeff: set the early suspend level before blank screen, so we wll do late resume after scree is lit */
pwrpriv->early_suspend.level = ANDROID_EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 20;
pwrpriv->early_suspend.suspend = rtw_early_suspend;
pwrpriv->early_suspend.resume = rtw_late_resume;
android_register_early_suspend(&pwrpriv->early_suspend);
}
void rtw_unregister_early_suspend(struct pwrctrl_priv *pwrpriv)
{
RTW_INFO("%s\n", __FUNCTION__);
rtw_set_do_late_resume(pwrpriv, _FALSE);
if (pwrpriv->early_suspend.suspend)
android_unregister_early_suspend(&pwrpriv->early_suspend);
pwrpriv->early_suspend.suspend = NULL;
pwrpriv->early_suspend.resume = NULL;
}
#endif /* CONFIG_ANDROID_POWER */
static void _rtw_ssmps(_adapter *adapter, struct sta_info *sta)
{
struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
issue_action_SM_PS_wait_ack(adapter , sta->phl_sta->mac_addr,
sta->phl_sta->asoc_cap.sm_ps, 3, 1);
if (sta->phl_sta->asoc_cap.sm_ps == SM_PS_STATIC) {
pmlmeext->txss_bk = sta->phl_sta->asoc_cap.nss_rx;
rtw_phl_sta_assoc_cap_process(sta->phl_sta, _TRUE);
sta->phl_sta->asoc_cap.nss_rx = 1;
sta->phl_sta->asoc_cap.stbc_ht_rx = 0;
sta->phl_sta->asoc_cap.stbc_vht_rx = 0;
sta->phl_sta->asoc_cap.stbc_he_rx = 0;
} else {
sta->phl_sta->asoc_cap.nss_rx = pmlmeext->txss_bk;
rtw_phl_sta_assoc_cap_process(sta->phl_sta, _FALSE);
}
rtw_phl_cmd_change_stainfo(adapter_to_dvobj(adapter)->phl,
sta->phl_sta,
STA_CHG_RAMASK,
NULL,
0,
PHL_CMD_DIRECTLY,
0);
}
void rtw_ssmps_enter(_adapter *adapter, struct sta_info *sta)
{
/* P2P spec v1.9 3.3.1 */
if (MLME_IS_AP(adapter) && !MLME_IS_GO(adapter))
return;
if (sta->phl_sta->asoc_cap.sm_ps == SM_PS_STATIC)
return;
RTW_INFO(ADPT_FMT" STA [" MAC_FMT "]\n", ADPT_ARG(adapter), MAC_ARG(sta->phl_sta->mac_addr));
sta->phl_sta->asoc_cap.sm_ps = SM_PS_STATIC;
_rtw_ssmps(adapter, sta);
}
void rtw_ssmps_leave(_adapter *adapter, struct sta_info *sta)
{
/* P2P spec v1.9 3.3.1 */
if (MLME_IS_AP(adapter) && !MLME_IS_GO(adapter))
return;
if (sta->phl_sta->asoc_cap.sm_ps == SM_PS_DISABLE)
return;
RTW_INFO(ADPT_FMT" STA [" MAC_FMT "] \n", ADPT_ARG(adapter), MAC_ARG(sta->phl_sta->mac_addr));
sta->phl_sta->asoc_cap.sm_ps = SM_PS_DISABLE;
_rtw_ssmps(adapter, sta);
}