diff --git a/hif/inc/hif.h b/hif/inc/hif.h index 18733a7ba1..961f65fe93 100644 --- a/hif/inc/hif.h +++ b/hif/inc/hif.h @@ -333,6 +333,22 @@ enum hif_event_type { /* Do check hif_hist_skip_event_record when adding new events */ }; +/** + * enum hif_system_pm_state - System PM state + * HIF_SYSTEM_PM_STATE_ON: System in active state + * HIF_SYSTEM_PM_STATE_BUS_RESUMING: bus resume in progress as part of + * system resume + * HIF_SYSTEM_PM_STATE_BUS_SUSPENDING: bus suspend in progress as part of + * system suspend + * HIF_SYSTEM_PM_STATE_BUS_SUSPENDED: bus suspended as part of system suspend + */ +enum hif_system_pm_state { + HIF_SYSTEM_PM_STATE_ON, + HIF_SYSTEM_PM_STATE_BUS_RESUMING, + HIF_SYSTEM_PM_STATE_BUS_SUSPENDING, + HIF_SYSTEM_PM_STATE_BUS_SUSPENDED, +}; + #ifdef WLAN_FEATURE_DP_EVENT_HISTORY #if defined(HIF_CONFIG_SLUB_DEBUG_ON) || defined(HIF_CE_DEBUG_DATA_BUF) @@ -1778,4 +1794,118 @@ static inline void hif_set_enable_detection(struct hif_opaque_softc *hif_ctx, bool value) {} #endif + +#ifdef SYSTEM_PM_CHECK +/** + * __hif_system_pm_set_state() - Set system pm state + * @hif: hif opaque handle + * @state: system state + * + * Return: None + */ +void __hif_system_pm_set_state(struct hif_opaque_softc *hif, + enum hif_system_pm_state state); + +/** + * hif_system_pm_set_state_on() - Set system pm state to ON + * @hif: hif opaque handle + * + * Return: None + */ +static inline +void hif_system_pm_set_state_on(struct hif_opaque_softc *hif) +{ + __hif_system_pm_set_state(hif, HIF_SYSTEM_PM_STATE_ON); +} + +/** + * hif_system_pm_set_state_resuming() - Set system pm state to resuming + * @hif: hif opaque handle + * + * Return: None + */ +static inline +void hif_system_pm_set_state_resuming(struct hif_opaque_softc *hif) +{ + __hif_system_pm_set_state(hif, HIF_SYSTEM_PM_STATE_BUS_RESUMING); +} + +/** + * hif_system_pm_set_state_suspending() - Set system pm state to suspending + * @hif: hif opaque handle + * + * Return: None + */ +static inline +void hif_system_pm_set_state_suspending(struct hif_opaque_softc *hif) +{ + __hif_system_pm_set_state(hif, HIF_SYSTEM_PM_STATE_BUS_SUSPENDING); +} + +/** + * hif_system_pm_set_state_suspended() - Set system pm state to suspended + * @hif: hif opaque handle + * + * Return: None + */ +static inline +void hif_system_pm_set_state_suspended(struct hif_opaque_softc *hif) +{ + __hif_system_pm_set_state(hif, HIF_SYSTEM_PM_STATE_BUS_SUSPENDED); +} + +/** + * hif_system_pm_get_state() - Get system pm state + * @hif: hif opaque handle + * + * Return: system state + */ +int32_t hif_system_pm_get_state(struct hif_opaque_softc *hif); + +/** + * hif_system_pm_state_check() - Check system state and trigger resume + * if required + * @hif: hif opaque handle + * + * Return: 0 if system is in on state else error code + */ +int hif_system_pm_state_check(struct hif_opaque_softc *hif); +#else +static inline +void __hif_system_pm_set_state(struct hif_opaque_softc *hif, + enum hif_system_pm_state state) +{ +} + +static inline +void hif_system_pm_set_state_on(struct hif_opaque_softc *hif) +{ +} + +static inline +void hif_system_pm_set_state_resuming(struct hif_opaque_softc *hif) +{ +} + +static inline +void hif_system_pm_set_state_suspending(struct hif_opaque_softc *hif) +{ +} + +static inline +void hif_system_pm_set_state_suspended(struct hif_opaque_softc *hif) +{ +} + +static inline +int32_t hif_system_pm_get_state(struct hif_opaque_softc *hif) +{ + return 0; +} + +static inline int hif_system_pm_state_check(struct hif_opaque_softc *hif) +{ + return 0; +} +#endif #endif /* _HIF_H_ */ diff --git a/hif/src/hif_main.c b/hif/src/hif_main.c index c67178d665..c93ae35370 100644 --- a/hif/src/hif_main.c +++ b/hif/src/hif_main.c @@ -898,6 +898,7 @@ struct hif_opaque_softc *hif_open(qdf_device_t qdf_ctx, qdf_atomic_init(&scn->active_grp_tasklet_cnt); qdf_atomic_init(&scn->link_suspended); qdf_atomic_init(&scn->tasklet_from_intr); + hif_system_pm_set_state_on(GET_HIF_OPAQUE_HDL(scn)); qdf_mem_copy(&scn->callbacks, cbk, sizeof(struct hif_driver_state_callbacks)); scn->bus_type = bus_type; @@ -2035,3 +2036,41 @@ void hif_set_ce_service_max_rx_ind_flush(struct hif_opaque_softc *hif, hif_ctx->ce_service_max_rx_ind_flush = ce_service_max_rx_ind_flush; } + +#ifdef SYSTEM_PM_CHECK +void __hif_system_pm_set_state(struct hif_opaque_softc *hif, + enum hif_system_pm_state state) +{ + struct hif_softc *hif_ctx = HIF_GET_SOFTC(hif); + + qdf_atomic_set(&hif_ctx->sys_pm_state, state); +} + +int32_t hif_system_pm_get_state(struct hif_opaque_softc *hif) +{ + struct hif_softc *hif_ctx = HIF_GET_SOFTC(hif); + + return qdf_atomic_read(&hif_ctx->sys_pm_state); +} + +int hif_system_pm_state_check(struct hif_opaque_softc *hif) +{ + struct hif_softc *hif_ctx = HIF_GET_SOFTC(hif); + int32_t sys_pm_state; + + if (!hif_ctx) { + hif_err("hif context is null"); + return -EFAULT; + } + + sys_pm_state = qdf_atomic_read(&hif_ctx->sys_pm_state); + if (sys_pm_state == HIF_SYSTEM_PM_STATE_BUS_SUSPENDING || + sys_pm_state == HIF_SYSTEM_PM_STATE_BUS_SUSPENDED) { + hif_info("Triggering system wakeup"); + qdf_pm_system_wakeup(); + return -EAGAIN; + } + + return 0; +} +#endif diff --git a/hif/src/hif_main.h b/hif/src/hif_main.h index f04cf1d2e9..a80ab6c8af 100644 --- a/hif/src/hif_main.h +++ b/hif/src/hif_main.h @@ -292,6 +292,9 @@ struct hif_softc { #ifdef HIF_DETECTION_LATENCY_ENABLE struct hif_latency_detect latency_detect; #endif +#ifdef SYSTEM_PM_CHECK + qdf_atomic_t sys_pm_state; +#endif }; static inline diff --git a/htc/htc_api.h b/htc/htc_api.h index 322c1cc071..18fd830b0b 100644 --- a/htc/htc_api.h +++ b/htc/htc_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014, 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, 2016-2021 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -860,4 +860,19 @@ void htc_print_credit_history(HTC_HANDLE htc, uint32_t count, print(print_priv, "HTC Credit History Feature is disabled"); } #endif + +#ifdef SYSTEM_PM_CHECK +/** + * htc_system_resume() - Send out any pending WMI/HTT + * messages pending in htc queues on system resume. + * @htc: HTC handle + * + * Return: None + */ +void htc_system_resume(HTC_HANDLE htc); +#else +static inline void htc_system_resume(HTC_HANDLE htc) +{ +} +#endif #endif /* _HTC_API_H_ */ diff --git a/htc/htc_packet.h b/htc/htc_packet.h index 68551303cc..78e0a3b95b 100644 --- a/htc/htc_packet.h +++ b/htc/htc_packet.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014, 2016-2017, 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, 2016-2017, 2019-2021 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -79,6 +79,9 @@ struct htc_tx_packet_info { /*Tag packet for runtime put in response or cleanup */ #define HTC_TX_PACKET_TAG_RTPM_PUT_RC (HTC_TX_PACKET_TAG_USER_DEFINED + 4) +#define HTC_TX_PACKET_SYSTEM_SUSPEND (HTC_TX_PACKET_TAG_USER_DEFINED + 5) +#define HTC_TX_PACKET_SYSTEM_RESUME (HTC_TX_PACKET_TAG_USER_DEFINED + 6) + #define HTC_TX_PACKET_FLAG_FIXUP_NETBUF (1 << 0) #define HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA (1 << 1) diff --git a/htc/htc_send.c b/htc/htc_send.c index 5663470da2..a7f9cdcbce 100644 --- a/htc/htc_send.c +++ b/htc/htc_send.c @@ -736,6 +736,7 @@ static QDF_STATUS htc_issue_packets(HTC_TARGET *target, int (*update_ep_padding_credit)(void *, int); void *ctx = NULL; bool rt_put_in_resp; + int32_t sys_state = HIF_SYSTEM_PM_STATE_ON; update_ep_padding_credit = pEndpoint->EpCallBacks.ep_padding_credit_update; @@ -851,6 +852,11 @@ static QDF_STATUS htc_issue_packets(HTC_TARGET *target, pEndpoint->UL_PipeID, false); } + if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_SYSTEM_SUSPEND) { + sys_state = hif_system_pm_get_state(target->hif_dev); + hif_system_pm_set_state_suspending(target->hif_dev); + } + htc_packet_set_magic_cookie(pPacket, HTC_PACKET_MAGIC_COOKIE); /* * For HTT messages without a response from fw, @@ -885,6 +891,12 @@ static QDF_STATUS htc_issue_packets(HTC_TARGET *target, if (status != QDF_STATUS_SUCCESS) { if (rt_put_in_resp) htc_dec_return_runtime_cnt((void *)target); + + if (pPacket->PktInfo.AsTx.Tag == + HTC_TX_PACKET_SYSTEM_SUSPEND) + __hif_system_pm_set_state(target->hif_dev, + sys_state); + if (pEndpoint->EpCallBacks.ep_padding_credit_update) { if (used_extra_tx_credit) { ctx = pEndpoint->EpCallBacks.pContext; @@ -1057,6 +1069,41 @@ htc_send_pkts_rtpm_dbgid_get(HTC_SERVICE_ID service_id) return rtpm_dbgid; } +#ifdef SYSTEM_PM_CHECK +/** + * extract_htc_system_resume_pkts(): Move system pm resume packets from endpoint + * into queue + * @endpoint: which enpoint to extract packets from + * @queue: a queue to store extracted packets in. + * + * Remove pm packets from the endpoint's tx queue and enqueue + * them into a queue + */ +static void extract_htc_system_resume_pkts(HTC_ENDPOINT *endpoint, + HTC_PACKET_QUEUE *queue) +{ + HTC_PACKET *packet; + + /* only WMI endpoint has power management packets */ + if (endpoint->service_id != WMI_CONTROL_SVC) + return; + + ITERATE_OVER_LIST_ALLOW_REMOVE(&endpoint->TxQueue.QueueHead, packet, + HTC_PACKET, ListLink) { + if (packet->PktInfo.AsTx.Tag == HTC_TX_PACKET_SYSTEM_RESUME) { + HTC_PACKET_REMOVE(&endpoint->TxQueue, packet); + HTC_PACKET_ENQUEUE(queue, packet); + } + } ITERATE_END +} +#else +static inline +void extract_htc_system_resume_pkts(HTC_ENDPOINT *endpoint, + HTC_PACKET_QUEUE *queue) +{ +} +#endif + /** * get_htc_send_packets_credit_based() - get packets based on available credits * @target: HTC target on which packets need to be sent @@ -1082,6 +1129,8 @@ static void get_htc_send_packets_credit_based(HTC_TARGET *target, bool do_pm_get = false; wlan_rtpm_dbgid rtpm_dbgid = 0; int ret; + HTC_PACKET_QUEUE sys_pm_queue; + bool sys_pm_check = false; /*** NOTE : the TX lock is held when this function is called ***/ AR_DEBUG_PRINTF(ATH_DEBUG_SEND, @@ -1090,8 +1139,16 @@ static void get_htc_send_packets_credit_based(HTC_TARGET *target, INIT_HTC_PACKET_QUEUE(&pm_queue); extract_htc_pm_packets(pEndpoint, &pm_queue); if (HTC_QUEUE_EMPTY(&pm_queue)) { - tx_queue = &pEndpoint->TxQueue; do_pm_get = true; + + INIT_HTC_PACKET_QUEUE(&sys_pm_queue); + extract_htc_system_resume_pkts(pEndpoint, &sys_pm_queue); + if (HTC_QUEUE_EMPTY(&sys_pm_queue)) { + tx_queue = &pEndpoint->TxQueue; + sys_pm_check = true; + } else { + tx_queue = &sys_pm_queue; + } } else { tx_queue = &pm_queue; } @@ -1127,6 +1184,13 @@ static void get_htc_send_packets_credit_based(HTC_TARGET *target, break; } + if (sys_pm_check && + hif_system_pm_state_check(target->hif_dev)) { + if (do_pm_get) + hif_pm_runtime_put(target->hif_dev, rtpm_dbgid); + break; + } + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Got head packet:%pK , Queue Depth: %d\n", pPacket, @@ -1275,6 +1339,11 @@ static void get_htc_send_packets(HTC_TARGET *target, hif_pm_runtime_put(target->hif_dev, rtpm_dbgid); break; } + + ret = hif_system_pm_state_check(target->hif_dev); + if (ret) + break; + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Got packet:%pK , New Queue Depth: %d\n", pPacket, @@ -2722,3 +2791,24 @@ struct ol_ath_htc_stats *ieee80211_ioctl_get_htc_stats(HTC_HANDLE HTCHandle) return &(target->htc_pkt_stats); } + +#ifdef SYSTEM_PM_CHECK +void htc_system_resume(HTC_HANDLE htc) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc); + HTC_ENDPOINT *endpoint = NULL; + int i; + + if (!target) + return; + + for (i = 0; i < ENDPOINT_MAX; i++) { + endpoint = &target->endpoint[i]; + + if (endpoint->service_id == 0) + continue; + + htc_try_send(target, endpoint, NULL); + } +} +#endif diff --git a/wmi/src/wmi_unified.c b/wmi/src/wmi_unified.c index 14e9d32ba2..0a10f2f2f7 100644 --- a/wmi/src/wmi_unified.c +++ b/wmi/src/wmi_unified.c @@ -1942,14 +1942,54 @@ static inline void wmi_unified_debug_dump(wmi_unified_t wmi_handle) "WMI_NON_TLV_TARGET")); } +#ifdef SYSTEM_PM_CHECK +/** + * wmi_set_system_pm_pkt_tag() - API to set tag for system pm packets + * @htc_tag: HTC tag + * @buf: wmi cmd buffer + * @cmd_id: cmd id + * + * Return: None + */ +static void wmi_set_system_pm_pkt_tag(uint16_t *htc_tag, wmi_buf_t buf, + uint32_t cmd_id) +{ + switch (cmd_id) { + case WMI_WOW_ENABLE_CMDID: + case WMI_PDEV_SUSPEND_CMDID: + *htc_tag = HTC_TX_PACKET_SYSTEM_SUSPEND; + break; + case WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID: + case WMI_PDEV_RESUME_CMDID: + *htc_tag = HTC_TX_PACKET_SYSTEM_RESUME; + break; + case WMI_D0_WOW_ENABLE_DISABLE_CMDID: + if (wmi_is_legacy_d0wow_disable_cmd(buf, cmd_id)) + *htc_tag = HTC_TX_PACKET_SYSTEM_RESUME; + else + *htc_tag = HTC_TX_PACKET_SYSTEM_SUSPEND; + break; + default: + break; + } +} +#else +static inline void wmi_set_system_pm_pkt_tag(uint16_t *htc_tag, wmi_buf_t buf, + uint32_t cmd_id) +{ +} +#endif + QDF_STATUS wmi_unified_cmd_send_fl(wmi_unified_t wmi_handle, wmi_buf_t buf, uint32_t len, uint32_t cmd_id, const char *func, uint32_t line) { HTC_PACKET *pkt; uint16_t htc_tag = 0; + bool rtpm_inprogress; - if (wmi_get_runtime_pm_inprogress(wmi_handle)) { + rtpm_inprogress = wmi_get_runtime_pm_inprogress(wmi_handle); + if (rtpm_inprogress) { htc_tag = wmi_handle->ops->wmi_set_htc_tx_tag(wmi_handle, buf, cmd_id); } else if (qdf_atomic_read(&wmi_handle->is_target_suspended) && @@ -2011,6 +2051,9 @@ QDF_STATUS wmi_unified_cmd_send_fl(wmi_unified_t wmi_handle, wmi_buf_t buf, return QDF_STATUS_E_NOMEM; } + if (!rtpm_inprogress) + wmi_set_system_pm_pkt_tag(&htc_tag, buf, cmd_id); + SET_HTC_PACKET_INFO_TX(pkt, NULL, qdf_nbuf_data(buf), len + sizeof(WMI_CMD_HDR),