diff --git a/dp/inc/cdp_txrx_bus.h b/dp/inc/cdp_txrx_bus.h index cda963e452..2c71b59041 100644 --- a/dp/inc/cdp_txrx_bus.h +++ b/dp/inc/cdp_txrx_bus.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, 2019-2020 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 @@ -69,4 +69,27 @@ static inline QDF_STATUS cdp_bus_resume(ol_txrx_soc_handle soc, return QDF_STATUS_E_NOSUPPORT; } +/** + * cdp_process_wow_ack() - Process wow ack response + * @soc: data path soc handle + * @pdev_id: id of dp pdev handle + * + * Do any required data path operations for target wow ack + * suspend response. + * + * Return: None + */ +static inline void cdp_process_wow_ack_rsp(ol_txrx_soc_handle soc, + uint8_t pdev_id) +{ + if (!soc || !soc->ops || !soc->ops->bus_ops) { + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, + "%s invalid instance", __func__); + return; + } + + if (soc->ops->bus_ops->process_wow_ack_rsp) + return soc->ops->bus_ops->process_wow_ack_rsp(soc, pdev_id); +} + #endif /* _CDP_TXRX_BUS_H_ */ diff --git a/dp/inc/cdp_txrx_ops.h b/dp/inc/cdp_txrx_ops.h index f29de12d4a..0f150a8cf1 100644 --- a/dp/inc/cdp_txrx_ops.h +++ b/dp/inc/cdp_txrx_ops.h @@ -1518,10 +1518,12 @@ struct cdp_tx_delay_ops { * struct cdp_bus_ops - mcl bus suspend/resume ops * @bus_suspend: handler for bus suspend * @bus_resume: handler for bus resume + * @process_wow_ack_rsp: handler for wow ack response */ struct cdp_bus_ops { QDF_STATUS (*bus_suspend)(struct cdp_soc_t *soc_hdl, uint8_t pdev_id); QDF_STATUS (*bus_resume)(struct cdp_soc_t *soc_hdl, uint8_t pdev_id); + void (*process_wow_ack_rsp)(struct cdp_soc_t *soc_hdl, uint8_t pdev_id); }; #endif diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 3937a902c1..2409c23d0d 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -201,6 +201,9 @@ static uint8_t dp_soc_ring_if_nss_offloaded(struct dp_soc *soc, /* Threshold for peer's cached buf queue beyond which frames are dropped */ #define DP_RX_CACHED_BUFQ_THRESH 64 +/* Budget to reap monitor status ring */ +#define DP_MON_REAP_BUDGET 1024 + /** * default_dscp_tid_map - Default DSCP-TID mapping * @@ -338,30 +341,43 @@ uint32_t dp_soc_get_mon_mask_for_interrupt_mode(struct dp_soc *soc, int intr_ctx } /* - * dp_service_mon_rings()- timer to reap monitor rings + * dp_service_mon_rings()- service monitor rings + * @soc: soc dp handle + * @quota: number of ring entry that can be serviced + * + * Return: None + * + */ +static void dp_service_mon_rings(struct dp_soc *soc, uint32_t quota) +{ + int ring = 0, work_done; + struct dp_pdev *pdev = NULL; + + for (ring = 0 ; ring < MAX_NUM_LMAC_HW; ring++) { + pdev = dp_get_pdev_for_lmac_id(soc, ring); + if (!pdev) + continue; + work_done = dp_mon_process(soc, ring, quota); + + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG, + FL("Reaped %d descs from Monitor rings"), + work_done); + } +} + +/* + * dp_mon_reap_timer_handler()- timer to reap monitor rings * reqd as we are not getting ppdu end interrupts * @arg: SoC Handle * * Return: * */ -static void dp_service_mon_rings(void *arg) +static void dp_mon_reap_timer_handler(void *arg) { struct dp_soc *soc = (struct dp_soc *)arg; - int ring = 0, work_done; - struct dp_pdev *pdev = NULL; - for (ring = 0 ; ring < MAX_NUM_LMAC_HW; ring++) { - pdev = dp_get_pdev_for_lmac_id(soc, ring); - if (!pdev) - continue; - work_done = dp_mon_process(soc, ring, - QCA_NAPI_BUDGET); - - QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG, - FL("Reaped %d descs from Monitor rings"), - work_done); - } + dp_service_mon_rings(soc, QCA_NAPI_BUDGET); qdf_timer_mod(&soc->mon_reap_timer, DP_INTR_POLL_TIMER_MS); } @@ -4670,8 +4686,8 @@ static QDF_STATUS dp_rxdma_ring_config(struct dp_soc *soc) * Needed until we enable ppdu end interrupts */ qdf_timer_init(soc->osdev, &soc->mon_reap_timer, - dp_service_mon_rings, (void *)soc, - QDF_TIMER_TYPE_WAKE_APPS); + dp_mon_reap_timer_handler, (void *)soc, + QDF_TIMER_TYPE_WAKE_APPS); soc->reap_timer_init = 1; return status; } @@ -10666,8 +10682,7 @@ static struct cdp_ipa_ops dp_ops_ipa = { static QDF_STATUS dp_bus_suspend(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) { struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl); - struct cdp_pdev *pdev = (struct cdp_pdev *) - dp_get_pdev_from_soc_pdev_id_wifi3(soc, pdev_id); + struct dp_pdev *pdev = dp_get_pdev_from_soc_pdev_id_wifi3(soc, pdev_id); int timeout = SUSPEND_DRAIN_WAIT; int drain_wait_delay = 50; /* 50 ms */ @@ -10677,7 +10692,7 @@ static QDF_STATUS dp_bus_suspend(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) } /* Abort if there are any pending TX packets */ - while (dp_get_tx_pending(pdev) > 0) { + while (dp_get_tx_pending((struct cdp_pdev *)pdev) > 0) { qdf_sleep(drain_wait_delay); if (timeout <= 0) { dp_err("TX frames are pending, abort suspend"); @@ -10689,22 +10704,70 @@ static QDF_STATUS dp_bus_suspend(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) if (soc->intr_mode == DP_INTR_POLL) qdf_timer_stop(&soc->int_timer); + /* Stop monitor reap timer and reap any pending frames in ring */ + if (pdev->rx_pktlog_mode != DP_RX_PKTLOG_DISABLED && + soc->reap_timer_init) { + qdf_timer_sync_cancel(&soc->mon_reap_timer); + dp_service_mon_rings(soc, DP_MON_REAP_BUDGET); + } + return QDF_STATUS_SUCCESS; } static QDF_STATUS dp_bus_resume(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) { struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl); + struct dp_pdev *pdev = dp_get_pdev_from_soc_pdev_id_wifi3(soc, pdev_id); + + if (qdf_unlikely(!pdev)) { + dp_err("pdev is NULL"); + return QDF_STATUS_E_INVAL; + } if (soc->intr_mode == DP_INTR_POLL) qdf_timer_mod(&soc->int_timer, DP_INTR_POLL_TIMER_MS); + /* Start monitor reap timer */ + if (pdev->rx_pktlog_mode != DP_RX_PKTLOG_DISABLED && + soc->reap_timer_init) + qdf_timer_mod(&soc->mon_reap_timer, + DP_INTR_POLL_TIMER_MS); + return QDF_STATUS_SUCCESS; } +/** + * dp_process_wow_ack_rsp() - process wow ack response + * @soc_hdl: datapath soc handle + * @pdev_id: data path pdev handle id + * + * Return: none + */ +static void dp_process_wow_ack_rsp(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) +{ + struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl); + struct dp_pdev *pdev = dp_get_pdev_from_soc_pdev_id_wifi3(soc, pdev_id); + + if (qdf_unlikely(!pdev)) { + dp_err("pdev is NULL"); + return; + } + + /* + * As part of wow enable FW disables the mon status ring and in wow ack + * response from FW reap mon status ring to make sure no packets pending + * in the ring. + */ + if (pdev->rx_pktlog_mode != DP_RX_PKTLOG_DISABLED && + soc->reap_timer_init) { + dp_service_mon_rings(soc, DP_MON_REAP_BUDGET); + } +} + static struct cdp_bus_ops dp_ops_bus = { .bus_suspend = dp_bus_suspend, - .bus_resume = dp_bus_resume + .bus_resume = dp_bus_resume, + .process_wow_ack_rsp = dp_process_wow_ack_rsp, }; #endif