From patchwork Thu Apr 7 22:36:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ricardo Martinez X-Patchwork-Id: 558766 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 68E9EC433F5 for ; Thu, 7 Apr 2022 22:37:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232117AbiDGWjO (ORCPT ); Thu, 7 Apr 2022 18:39:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40952 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229703AbiDGWjN (ORCPT ); Thu, 7 Apr 2022 18:39:13 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A1816129253; Thu, 7 Apr 2022 15:37:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1649371031; x=1680907031; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=MHiLlcSaMnahwidQH1EnOY42tA4Hy/pUqwVnkznAwCQ=; b=XpScJ68zD77lDwQqT0+MZZg/tjOVIs7gv1jLfKfttlGOjARdkW5ma4yl vAPswn3706MVASev0pusto34EH8Y6NLAtvHiv13HP3yoK5SJPNzBAt8NN 4wCorJvhhkQ8xDGkNgf47SCSs3Bg7ht0LqrTju3zGyR6hl1aQcGMYT8iq IZeNgFDk4rPQmLk1tjr2qB0J6okktcgmS45/2lJBfClPnxmcWGWvs08yb IYZJFlV8hSYNA6g++NfV8Ps3gfXdBFPW5HQWxTKsrWfGIuluSKZiDFpy/ qme3dXLbdHfnu5ctByQDfr31aJIsWXuXGJtLiT1JYGc0xL12r+vmCDahh Q==; X-IronPort-AV: E=McAfee;i="6400,9594,10310"; a="261449303" X-IronPort-AV: E=Sophos;i="5.90,242,1643702400"; d="scan'208";a="261449303" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Apr 2022 15:37:11 -0700 X-IronPort-AV: E=Sophos;i="5.90,242,1643702400"; d="scan'208";a="659242870" Received: from rmarti10-desk.jf.intel.com ([134.134.150.146]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Apr 2022 15:37:11 -0700 From: Ricardo Martinez To: netdev@vger.kernel.org, linux-wireless@vger.kernel.org Cc: kuba@kernel.org, davem@davemloft.net, johannes@sipsolutions.net, ryazanov.s.a@gmail.com, loic.poulain@linaro.org, m.chetan.kumar@intel.com, chandrashekar.devegowda@intel.com, linuxwwan@intel.com, chiranjeevi.rapolu@linux.intel.com, haijun.liu@mediatek.com, amir.hanania@intel.com, andriy.shevchenko@linux.intel.com, dinesh.sharma@intel.com, eliot.lee@intel.com, ilpo.johannes.jarvinen@intel.com, moises.veleta@intel.com, pierre-louis.bossart@intel.com, muralidharan.sethuraman@intel.com, Soumya.Prakash.Mishra@intel.com, sreehari.kancharla@intel.com, madhusmita.sahu@intel.com, Ricardo Martinez Subject: [PATCH net-next v6 01/13] list: Add list_next_entry_circular() and list_prev_entry_circular() Date: Thu, 7 Apr 2022 15:36:17 -0700 Message-Id: <20220407223629.21487-2-ricardo.martinez@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220407223629.21487-1-ricardo.martinez@linux.intel.com> References: <20220407223629.21487-1-ricardo.martinez@linux.intel.com> Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org Add macros to get the next or previous entries and wraparound if needed. For example, calling list_next_entry_circular() on the last element should return the first element in the list. Signed-off-by: Ricardo Martinez Reviewed-by: Andy Shevchenko --- include/linux/list.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/include/linux/list.h b/include/linux/list.h index d7d2bfa1a365..c36e3b9a651b 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -563,6 +563,19 @@ static inline void list_splice_tail_init(struct list_head *list, #define list_next_entry(pos, member) \ list_entry((pos)->member.next, typeof(*(pos)), member) +/** + * list_next_entry_circular - get the next element in list + * @pos: the type * to cursor. + * @head: the list head to take the element from. + * @member: the name of the list_head within the struct. + * + * Wraparound if pos is the last element (return the first element). + * Note, that list is expected to be not empty. + */ +#define list_next_entry_circular(pos, head, member) \ + (list_is_last(&(pos)->member, head) ? \ + list_first_entry(head, typeof(*(pos)), member) : list_next_entry(pos, member)) + /** * list_prev_entry - get the prev element in list * @pos: the type * to cursor @@ -571,6 +584,19 @@ static inline void list_splice_tail_init(struct list_head *list, #define list_prev_entry(pos, member) \ list_entry((pos)->member.prev, typeof(*(pos)), member) +/** + * list_prev_entry_circular - get the prev element in list + * @pos: the type * to cursor. + * @head: the list head to take the element from. + * @member: the name of the list_head within the struct. + * + * Wraparound if pos is the first element (return the last element). + * Note, that list is expected to be not empty. + */ +#define list_prev_entry_circular(pos, head, member) \ + (list_is_first(&(pos)->member, head) ? \ + list_last_entry(head, typeof(*(pos)), member) : list_prev_entry(pos, member)) + /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. From patchwork Thu Apr 7 22:36:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ricardo Martinez X-Patchwork-Id: 559155 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AB85DC433EF for ; Thu, 7 Apr 2022 22:37:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232159AbiDGWja (ORCPT ); Thu, 7 Apr 2022 18:39:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41388 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232138AbiDGWjS (ORCPT ); Thu, 7 Apr 2022 18:39:18 -0400 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ED5B4129E8E; Thu, 7 Apr 2022 15:37:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1649371034; x=1680907034; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=5J9owCtcRz1q2ZAwXCNnDOxJ5NfSfuM8HHAZCQ222qo=; b=nDBD1K78Qtuws3dl4Y0LwdbP7cjXOzpKgIBfJs/NW19tSbTvBpivEICs Ys1Ph9o0lLKhr77/yrXXAs2Q9lmsrWn8h6OfgFk1+GpcTEhZiUu6ICHn1 zuDCGuteuNbPIThSNpAmOr5nMdEX5wSDSoSqjUT6MlM5/whe3jM4VEcjD 9Dcc02BengPYYK4C3gz/An31EIHExlj5srfXIjF5yNDzxJn7ThpJ0mKSX fZtM3U7txRtLjr4uyhJWN++GTaeTOSu1A1tsaMlA6NAPyoN2/P7ILG50w kGPcgiii00+QBgVWGZEm3Ik4g43qubMS0dS26gtEZARvYhcvXS1Q4lJfB Q==; X-IronPort-AV: E=McAfee;i="6400,9594,10310"; a="243589605" X-IronPort-AV: E=Sophos;i="5.90,242,1643702400"; d="scan'208";a="243589605" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Apr 2022 15:37:12 -0700 X-IronPort-AV: E=Sophos;i="5.90,242,1643702400"; d="scan'208";a="659242902" Received: from rmarti10-desk.jf.intel.com ([134.134.150.146]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Apr 2022 15:37:12 -0700 From: Ricardo Martinez To: netdev@vger.kernel.org, linux-wireless@vger.kernel.org Cc: kuba@kernel.org, davem@davemloft.net, johannes@sipsolutions.net, ryazanov.s.a@gmail.com, loic.poulain@linaro.org, m.chetan.kumar@intel.com, chandrashekar.devegowda@intel.com, linuxwwan@intel.com, chiranjeevi.rapolu@linux.intel.com, haijun.liu@mediatek.com, amir.hanania@intel.com, andriy.shevchenko@linux.intel.com, dinesh.sharma@intel.com, eliot.lee@intel.com, ilpo.johannes.jarvinen@intel.com, moises.veleta@intel.com, pierre-louis.bossart@intel.com, muralidharan.sethuraman@intel.com, Soumya.Prakash.Mishra@intel.com, sreehari.kancharla@intel.com, madhusmita.sahu@intel.com, Ricardo Martinez Subject: [PATCH net-next v6 11/13] net: wwan: t7xx: Runtime PM Date: Thu, 7 Apr 2022 15:36:27 -0700 Message-Id: <20220407223629.21487-12-ricardo.martinez@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220407223629.21487-1-ricardo.martinez@linux.intel.com> References: <20220407223629.21487-1-ricardo.martinez@linux.intel.com> Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Haijun Liu Enables runtime power management callbacks including runtime_suspend and runtime_resume. Autosuspend is used to prevent overhead by frequent wake-ups. Signed-off-by: Haijun Liu Signed-off-by: Chandrashekar Devegowda Co-developed-by: Eliot Lee Signed-off-by: Eliot Lee Signed-off-by: Ricardo Martinez --- drivers/net/wwan/t7xx/t7xx_hif_cldma.c | 14 ++++++++++++++ drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c | 17 +++++++++++++++++ drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.c | 15 +++++++++++++++ drivers/net/wwan/t7xx/t7xx_pci.c | 22 ++++++++++++++++++++++ 4 files changed, 68 insertions(+) diff --git a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c index b71d76d4db51..3f3bb82a0543 100644 --- a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c +++ b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -266,6 +267,8 @@ static void t7xx_cldma_rx_done(struct work_struct *work) t7xx_cldma_clear_ip_busy(&md_ctrl->hw_info); t7xx_cldma_hw_irq_en_txrx(&md_ctrl->hw_info, queue->index, MTK_RX); t7xx_cldma_hw_irq_en_eq(&md_ctrl->hw_info, queue->index, MTK_RX); + pm_runtime_mark_last_busy(md_ctrl->dev); + pm_runtime_put_autosuspend(md_ctrl->dev); } static int t7xx_cldma_gpd_tx_collect(struct cldma_queue *queue) @@ -377,6 +380,9 @@ static void t7xx_cldma_tx_done(struct work_struct *work) t7xx_cldma_hw_irq_en_txrx(hw_info, queue->index, MTK_TX); } spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); + + pm_runtime_mark_last_busy(md_ctrl->dev); + pm_runtime_put_autosuspend(md_ctrl->dev); } static void t7xx_cldma_ring_free(struct cldma_ctrl *md_ctrl, @@ -585,6 +591,7 @@ static void t7xx_cldma_irq_work_cb(struct cldma_ctrl *md_ctrl) if (l2_tx_int & (TXRX_STATUS_BITMASK | EMPTY_STATUS_BITMASK)) { for_each_set_bit(i, (unsigned long *)&l2_tx_int, L2_INT_BIT_COUNT) { if (i < CLDMA_TXQ_NUM) { + pm_runtime_get(md_ctrl->dev); t7xx_cldma_hw_irq_dis_eq(hw_info, i, MTK_TX); t7xx_cldma_hw_irq_dis_txrx(hw_info, i, MTK_TX); queue_work(md_ctrl->txq[i].worker, @@ -609,6 +616,7 @@ static void t7xx_cldma_irq_work_cb(struct cldma_ctrl *md_ctrl) if (l2_rx_int & (TXRX_STATUS_BITMASK | EMPTY_STATUS_BITMASK)) { l2_rx_int |= l2_rx_int >> CLDMA_RXQ_NUM; for_each_set_bit(i, (unsigned long *)&l2_rx_int, CLDMA_RXQ_NUM) { + pm_runtime_get(md_ctrl->dev); t7xx_cldma_hw_irq_dis_eq(hw_info, i, MTK_RX); t7xx_cldma_hw_irq_dis_txrx(hw_info, i, MTK_RX); queue_work(md_ctrl->rxq[i].worker, &md_ctrl->rxq[i].cldma_work); @@ -939,6 +947,10 @@ int t7xx_cldma_send_skb(struct cldma_ctrl *md_ctrl, int qno, struct sk_buff *skb if (qno >= CLDMA_TXQ_NUM) return -EINVAL; + ret = pm_runtime_resume_and_get(md_ctrl->dev); + if (ret < 0 && ret != -EACCES) + return ret; + queue = &md_ctrl->txq[qno]; spin_lock_irqsave(&md_ctrl->cldma_lock, flags); @@ -982,6 +994,8 @@ int t7xx_cldma_send_skb(struct cldma_ctrl *md_ctrl, int qno, struct sk_buff *skb } while (!ret); allow_sleep: + pm_runtime_mark_last_busy(md_ctrl->dev); + pm_runtime_put_autosuspend(md_ctrl->dev); return ret; } diff --git a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c index 6aa10536dd9c..1b029cbc28ff 100644 --- a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c +++ b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -911,6 +912,7 @@ static void t7xx_dpmaif_rxq_work(struct work_struct *work) { struct dpmaif_rx_queue *rxq = container_of(work, struct dpmaif_rx_queue, dpmaif_rxq_work); struct dpmaif_ctrl *dpmaif_ctrl = rxq->dpmaif_ctrl; + int ret; atomic_set(&rxq->rx_processing, 1); /* Ensure rx_processing is changed to 1 before actually begin RX flow */ @@ -922,7 +924,14 @@ static void t7xx_dpmaif_rxq_work(struct work_struct *work) return; } + ret = pm_runtime_resume_and_get(dpmaif_ctrl->dev); + if (ret < 0 && ret != -EACCES) + return; + t7xx_dpmaif_do_rx(dpmaif_ctrl, rxq); + + pm_runtime_mark_last_busy(dpmaif_ctrl->dev); + pm_runtime_put_autosuspend(dpmaif_ctrl->dev); atomic_set(&rxq->rx_processing, 0); } @@ -1124,11 +1133,19 @@ static void t7xx_dpmaif_bat_release_work(struct work_struct *work) { struct dpmaif_ctrl *dpmaif_ctrl = container_of(work, struct dpmaif_ctrl, bat_release_work); struct dpmaif_rx_queue *rxq; + int ret; + + ret = pm_runtime_resume_and_get(dpmaif_ctrl->dev); + if (ret < 0 && ret != -EACCES) + return; /* ALL RXQ use one BAT table, so choose DPF_RX_QNO_DFT */ rxq = &dpmaif_ctrl->rxq[DPF_RX_QNO_DFT]; t7xx_dpmaif_bat_release_and_add(rxq); t7xx_dpmaif_frag_bat_release_and_add(rxq); + + pm_runtime_mark_last_busy(dpmaif_ctrl->dev); + pm_runtime_put_autosuspend(dpmaif_ctrl->dev); } int t7xx_dpmaif_bat_rel_wq_alloc(struct dpmaif_ctrl *dpmaif_ctrl) diff --git a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.c b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.c index b6c43c538a10..026821a98c9d 100644 --- a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.c +++ b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -161,6 +162,10 @@ static void t7xx_dpmaif_tx_done(struct work_struct *work) struct dpmaif_hw_info *hw_info; int ret; + ret = pm_runtime_resume_and_get(dpmaif_ctrl->dev); + if (ret < 0 && ret != -EACCES) + return; + hw_info = &dpmaif_ctrl->hw_info; ret = t7xx_dpmaif_tx_release(dpmaif_ctrl, txq->index, txq->drb_size_cnt); if (ret == -EAGAIN || @@ -174,6 +179,9 @@ static void t7xx_dpmaif_tx_done(struct work_struct *work) t7xx_dpmaif_clr_ip_busy_sts(hw_info); t7xx_dpmaif_unmask_ulq_intr(hw_info, txq->index); } + + pm_runtime_mark_last_busy(dpmaif_ctrl->dev); + pm_runtime_put_autosuspend(dpmaif_ctrl->dev); } static void t7xx_setup_msg_drb(struct dpmaif_ctrl *dpmaif_ctrl, unsigned int q_num, @@ -420,6 +428,7 @@ static void t7xx_do_tx_hw_push(struct dpmaif_ctrl *dpmaif_ctrl) static int t7xx_dpmaif_tx_hw_push_thread(void *arg) { struct dpmaif_ctrl *dpmaif_ctrl = arg; + int ret; while (!kthread_should_stop()) { if (t7xx_tx_lists_are_all_empty(dpmaif_ctrl) || @@ -434,7 +443,13 @@ static int t7xx_dpmaif_tx_hw_push_thread(void *arg) break; } + ret = pm_runtime_resume_and_get(dpmaif_ctrl->dev); + if (ret < 0 && ret != -EACCES) + return ret; + t7xx_do_tx_hw_push(dpmaif_ctrl); + pm_runtime_mark_last_busy(dpmaif_ctrl->dev); + pm_runtime_put_autosuspend(dpmaif_ctrl->dev); } return 0; diff --git a/drivers/net/wwan/t7xx/t7xx_pci.c b/drivers/net/wwan/t7xx/t7xx_pci.c index 564147664af0..400c11f7b31e 100644 --- a/drivers/net/wwan/t7xx/t7xx_pci.c +++ b/drivers/net/wwan/t7xx/t7xx_pci.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "t7xx_mhccif.h" @@ -44,6 +45,7 @@ #define T7XX_PCI_EREG_BASE 2 #define PM_ACK_TIMEOUT_MS 1500 +#define PM_AUTOSUSPEND_MS 20000 #define PM_RESOURCE_POLL_TIMEOUT_US 10000 #define PM_RESOURCE_POLL_STEP_US 100 @@ -82,6 +84,8 @@ static int t7xx_pci_pm_init(struct t7xx_pci_dev *t7xx_dev) DPM_FLAG_NO_DIRECT_COMPLETE); iowrite32(T7XX_L1_BIT(0), IREG_BASE(t7xx_dev) + DISABLE_ASPM_LOWPWR); + pm_runtime_set_autosuspend_delay(&pdev->dev, PM_AUTOSUSPEND_MS); + pm_runtime_use_autosuspend(&pdev->dev); return t7xx_wait_pm_config(t7xx_dev); } @@ -96,6 +100,8 @@ void t7xx_pci_pm_init_late(struct t7xx_pci_dev *t7xx_dev) D2H_INT_RESUME_ACK_AP); iowrite32(T7XX_L1_BIT(0), IREG_BASE(t7xx_dev) + ENABLE_ASPM_LOWPWR); atomic_set(&t7xx_dev->md_pm_state, MTK_PM_RESUMED); + + pm_runtime_put_noidle(&t7xx_dev->pdev->dev); } static int t7xx_pci_pm_reinit(struct t7xx_pci_dev *t7xx_dev) @@ -104,6 +110,9 @@ static int t7xx_pci_pm_reinit(struct t7xx_pci_dev *t7xx_dev) * so just roll back PM setting to the init setting. */ atomic_set(&t7xx_dev->md_pm_state, MTK_PM_INIT); + + pm_runtime_get_noresume(&t7xx_dev->pdev->dev); + iowrite32(T7XX_L1_BIT(0), IREG_BASE(t7xx_dev) + DISABLE_ASPM_LOWPWR); return t7xx_wait_pm_config(t7xx_dev); } @@ -403,6 +412,7 @@ static int __t7xx_pci_pm_resume(struct pci_dev *pdev, bool state_check) t7xx_dev->rgu_pci_irq_en = true; t7xx_pcie_mac_set_int(t7xx_dev, SAP_RGU_INT); iowrite32(T7XX_L1_BIT(0), IREG_BASE(t7xx_dev) + ENABLE_ASPM_LOWPWR); + pm_runtime_mark_last_busy(&pdev->dev); atomic_set(&t7xx_dev->md_pm_state, MTK_PM_RESUMED); return ret; @@ -439,6 +449,16 @@ static int t7xx_pci_pm_thaw(struct device *dev) return __t7xx_pci_pm_resume(to_pci_dev(dev), false); } +static int t7xx_pci_pm_runtime_suspend(struct device *dev) +{ + return __t7xx_pci_pm_suspend(to_pci_dev(dev)); +} + +static int t7xx_pci_pm_runtime_resume(struct device *dev) +{ + return __t7xx_pci_pm_resume(to_pci_dev(dev), true); +} + static const struct dev_pm_ops t7xx_pci_pm_ops = { .suspend = t7xx_pci_pm_suspend, .resume = t7xx_pci_pm_resume, @@ -448,6 +468,8 @@ static const struct dev_pm_ops t7xx_pci_pm_ops = { .poweroff = t7xx_pci_pm_suspend, .restore = t7xx_pci_pm_resume, .restore_noirq = t7xx_pci_pm_resume_noirq, + .runtime_suspend = t7xx_pci_pm_runtime_suspend, + .runtime_resume = t7xx_pci_pm_runtime_resume }; static int t7xx_request_irq(struct pci_dev *pdev) From patchwork Thu Apr 7 22:36:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ricardo Martinez X-Patchwork-Id: 559154 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 21E8CC4332F for ; Thu, 7 Apr 2022 22:37:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232195AbiDGWjl (ORCPT ); Thu, 7 Apr 2022 18:39:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41542 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232118AbiDGWjU (ORCPT ); Thu, 7 Apr 2022 18:39:20 -0400 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 32016129E96; Thu, 7 Apr 2022 15:37:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1649371035; x=1680907035; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=EDtSOSod4MlBtV/lqhUPAE5l5Od4E5cFtq6YdfMt5u4=; b=L8t7VLc9WeGLK1GqFQ8LwUyihLtYXKjWGxAX02UWdruxmqTP+mff/IrY 6Fucj1DMNhKY6vrnjncc76Q/nk4AUhVv1mLjrpOcKp8lFaJZzU9RUfGnj jEqzRbdX6r3k/Ecur8IT9bE3F9/9z2nMtd5ActNOzQCN7K/eZ8go34DaW 2Vy9ut0SoXDyaBQJqLlfvKi1fYv1AKpBF3EuBSduksdHpGB65FWQdib9w 7cxsad9Fpn1Nq4+QTsWDHz0kXzXC2u4wfPZqOqeVwoOXmCCMQngmCjnl1 LfiX3+BMXIFExmueJgoKvK+RtMfDfiHAMfgYmAU6ldjIZlW+bc4Y78NwE A==; X-IronPort-AV: E=McAfee;i="6400,9594,10310"; a="243589608" X-IronPort-AV: E=Sophos;i="5.90,242,1643702400"; d="scan'208";a="243589608" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Apr 2022 15:37:12 -0700 X-IronPort-AV: E=Sophos;i="5.90,242,1643702400"; d="scan'208";a="659242905" Received: from rmarti10-desk.jf.intel.com ([134.134.150.146]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Apr 2022 15:37:12 -0700 From: Ricardo Martinez To: netdev@vger.kernel.org, linux-wireless@vger.kernel.org Cc: kuba@kernel.org, davem@davemloft.net, johannes@sipsolutions.net, ryazanov.s.a@gmail.com, loic.poulain@linaro.org, m.chetan.kumar@intel.com, chandrashekar.devegowda@intel.com, linuxwwan@intel.com, chiranjeevi.rapolu@linux.intel.com, haijun.liu@mediatek.com, amir.hanania@intel.com, andriy.shevchenko@linux.intel.com, dinesh.sharma@intel.com, eliot.lee@intel.com, ilpo.johannes.jarvinen@intel.com, moises.veleta@intel.com, pierre-louis.bossart@intel.com, muralidharan.sethuraman@intel.com, Soumya.Prakash.Mishra@intel.com, sreehari.kancharla@intel.com, madhusmita.sahu@intel.com, Ricardo Martinez Subject: [PATCH net-next v6 12/13] net: wwan: t7xx: Device deep sleep lock/unlock Date: Thu, 7 Apr 2022 15:36:28 -0700 Message-Id: <20220407223629.21487-13-ricardo.martinez@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220407223629.21487-1-ricardo.martinez@linux.intel.com> References: <20220407223629.21487-1-ricardo.martinez@linux.intel.com> Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Haijun Liu Introduce the mechanism to lock/unlock the device 'deep sleep' mode. When the PCIe link state is L1.2 or L2, the host side still can keep the device is in D0 state from the host side point of view. At the same time, if the device's 'deep sleep' mode is unlocked, the device will go to 'deep sleep' while it is still in D0 state on the host side. Signed-off-by: Haijun Liu Signed-off-by: Chandrashekar Devegowda Co-developed-by: Ricardo Martinez Signed-off-by: Ricardo Martinez --- drivers/net/wwan/t7xx/t7xx_hif_cldma.c | 12 +++ drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c | 14 +++- drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.c | 41 +++++++--- drivers/net/wwan/t7xx/t7xx_mhccif.c | 3 + drivers/net/wwan/t7xx/t7xx_pci.c | 93 ++++++++++++++++++++++ drivers/net/wwan/t7xx/t7xx_pci.h | 10 +++ 6 files changed, 158 insertions(+), 15 deletions(-) diff --git a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c index 3f3bb82a0543..e78995ecb63e 100644 --- a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c +++ b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c @@ -951,6 +951,7 @@ int t7xx_cldma_send_skb(struct cldma_ctrl *md_ctrl, int qno, struct sk_buff *skb if (ret < 0 && ret != -EACCES) return ret; + t7xx_pci_disable_sleep(md_ctrl->t7xx_dev); queue = &md_ctrl->txq[qno]; spin_lock_irqsave(&md_ctrl->cldma_lock, flags); @@ -972,6 +973,11 @@ int t7xx_cldma_send_skb(struct cldma_ctrl *md_ctrl, int qno, struct sk_buff *skb queue->tx_next = list_next_entry_circular(tx_req, gpd_ring, entry); spin_unlock_irqrestore(&queue->ring_lock, flags); + if (!t7xx_pci_sleep_disable_complete(md_ctrl->t7xx_dev)) { + ret = -ETIMEDOUT; + break; + } + /* Protect the access to the modem for queues operations (resume/start) * which access shared locations by all the queues. * cldma_lock is independent of ring_lock which is per queue. @@ -984,6 +990,11 @@ int t7xx_cldma_send_skb(struct cldma_ctrl *md_ctrl, int qno, struct sk_buff *skb } spin_unlock_irqrestore(&queue->ring_lock, flags); + if (!t7xx_pci_sleep_disable_complete(md_ctrl->t7xx_dev)) { + ret = -ETIMEDOUT; + break; + } + if (!t7xx_cldma_hw_queue_status(&md_ctrl->hw_info, qno, MTK_TX)) { spin_lock_irqsave(&md_ctrl->cldma_lock, flags); t7xx_cldma_hw_resume_queue(&md_ctrl->hw_info, qno, MTK_TX); @@ -994,6 +1005,7 @@ int t7xx_cldma_send_skb(struct cldma_ctrl *md_ctrl, int qno, struct sk_buff *skb } while (!ret); allow_sleep: + t7xx_pci_enable_sleep(md_ctrl->t7xx_dev); pm_runtime_mark_last_busy(md_ctrl->dev); pm_runtime_put_autosuspend(md_ctrl->dev); return ret; diff --git a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c index 1b029cbc28ff..57ec49f9fc11 100644 --- a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c +++ b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c @@ -928,8 +928,11 @@ static void t7xx_dpmaif_rxq_work(struct work_struct *work) if (ret < 0 && ret != -EACCES) return; - t7xx_dpmaif_do_rx(dpmaif_ctrl, rxq); + t7xx_pci_disable_sleep(dpmaif_ctrl->t7xx_dev); + if (t7xx_pci_sleep_disable_complete(dpmaif_ctrl->t7xx_dev)) + t7xx_dpmaif_do_rx(dpmaif_ctrl, rxq); + t7xx_pci_enable_sleep(dpmaif_ctrl->t7xx_dev); pm_runtime_mark_last_busy(dpmaif_ctrl->dev); pm_runtime_put_autosuspend(dpmaif_ctrl->dev); atomic_set(&rxq->rx_processing, 0); @@ -1139,11 +1142,16 @@ static void t7xx_dpmaif_bat_release_work(struct work_struct *work) if (ret < 0 && ret != -EACCES) return; + t7xx_pci_disable_sleep(dpmaif_ctrl->t7xx_dev); + /* ALL RXQ use one BAT table, so choose DPF_RX_QNO_DFT */ rxq = &dpmaif_ctrl->rxq[DPF_RX_QNO_DFT]; - t7xx_dpmaif_bat_release_and_add(rxq); - t7xx_dpmaif_frag_bat_release_and_add(rxq); + if (t7xx_pci_sleep_disable_complete(dpmaif_ctrl->t7xx_dev)) { + t7xx_dpmaif_bat_release_and_add(rxq); + t7xx_dpmaif_frag_bat_release_and_add(rxq); + } + t7xx_pci_enable_sleep(dpmaif_ctrl->t7xx_dev); pm_runtime_mark_last_busy(dpmaif_ctrl->dev); pm_runtime_put_autosuspend(dpmaif_ctrl->dev); } diff --git a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.c b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.c index 026821a98c9d..e999d87e0483 100644 --- a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.c +++ b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.c @@ -166,20 +166,25 @@ static void t7xx_dpmaif_tx_done(struct work_struct *work) if (ret < 0 && ret != -EACCES) return; - hw_info = &dpmaif_ctrl->hw_info; - ret = t7xx_dpmaif_tx_release(dpmaif_ctrl, txq->index, txq->drb_size_cnt); - if (ret == -EAGAIN || - (t7xx_dpmaif_ul_clr_done(hw_info, txq->index) && - t7xx_dpmaif_drb_ring_not_empty(txq))) { - queue_work(dpmaif_ctrl->txq[txq->index].worker, - &dpmaif_ctrl->txq[txq->index].dpmaif_tx_work); - /* Give the device time to enter the low power state */ - t7xx_dpmaif_clr_ip_busy_sts(hw_info); - } else { - t7xx_dpmaif_clr_ip_busy_sts(hw_info); - t7xx_dpmaif_unmask_ulq_intr(hw_info, txq->index); + /* The device may be in low power state. Disable sleep if needed */ + t7xx_pci_disable_sleep(dpmaif_ctrl->t7xx_dev); + if (t7xx_pci_sleep_disable_complete(dpmaif_ctrl->t7xx_dev)) { + hw_info = &dpmaif_ctrl->hw_info; + ret = t7xx_dpmaif_tx_release(dpmaif_ctrl, txq->index, txq->drb_size_cnt); + if (ret == -EAGAIN || + (t7xx_dpmaif_ul_clr_done(hw_info, txq->index) && + t7xx_dpmaif_drb_ring_not_empty(txq))) { + queue_work(dpmaif_ctrl->txq[txq->index].worker, + &dpmaif_ctrl->txq[txq->index].dpmaif_tx_work); + /* Give the device time to enter the low power state */ + t7xx_dpmaif_clr_ip_busy_sts(hw_info); + } else { + t7xx_dpmaif_clr_ip_busy_sts(hw_info); + t7xx_dpmaif_unmask_ulq_intr(hw_info, txq->index); + } } + t7xx_pci_enable_sleep(dpmaif_ctrl->t7xx_dev); pm_runtime_mark_last_busy(dpmaif_ctrl->dev); pm_runtime_put_autosuspend(dpmaif_ctrl->dev); } @@ -402,6 +407,8 @@ static int t7xx_txq_burst_send_skb(struct dpmaif_tx_queue *txq) static void t7xx_do_tx_hw_push(struct dpmaif_ctrl *dpmaif_ctrl) { + bool wait_disable_sleep = true; + do { struct dpmaif_tx_queue *txq; int drb_send_cnt; @@ -417,6 +424,14 @@ static void t7xx_do_tx_hw_push(struct dpmaif_ctrl *dpmaif_ctrl) continue; } + /* Wait for the PCIe resource to unlock */ + if (wait_disable_sleep) { + if (!t7xx_pci_sleep_disable_complete(dpmaif_ctrl->t7xx_dev)) + return; + + wait_disable_sleep = false; + } + t7xx_dpmaif_ul_update_hw_drb_cnt(&dpmaif_ctrl->hw_info, txq->index, drb_send_cnt * DPMAIF_UL_DRB_SIZE_WORD); @@ -447,7 +462,9 @@ static int t7xx_dpmaif_tx_hw_push_thread(void *arg) if (ret < 0 && ret != -EACCES) return ret; + t7xx_pci_disable_sleep(dpmaif_ctrl->t7xx_dev); t7xx_do_tx_hw_push(dpmaif_ctrl); + t7xx_pci_enable_sleep(dpmaif_ctrl->t7xx_dev); pm_runtime_mark_last_busy(dpmaif_ctrl->dev); pm_runtime_put_autosuspend(dpmaif_ctrl->dev); } diff --git a/drivers/net/wwan/t7xx/t7xx_mhccif.c b/drivers/net/wwan/t7xx/t7xx_mhccif.c index 4bb452f5ccff..3ee18d46f8d2 100644 --- a/drivers/net/wwan/t7xx/t7xx_mhccif.c +++ b/drivers/net/wwan/t7xx/t7xx_mhccif.c @@ -59,6 +59,9 @@ static irqreturn_t t7xx_mhccif_isr_thread(int irq, void *data) t7xx_mhccif_clear_interrupts(t7xx_dev, int_status); + if (int_status & D2H_INT_DS_LOCK_ACK) + complete_all(&t7xx_dev->sleep_lock_acquire); + if (int_status & D2H_INT_SR_ACK) complete(&t7xx_dev->pm_sr_ack); diff --git a/drivers/net/wwan/t7xx/t7xx_pci.c b/drivers/net/wwan/t7xx/t7xx_pci.c index 400c11f7b31e..ce4b22b61f68 100644 --- a/drivers/net/wwan/t7xx/t7xx_pci.c +++ b/drivers/net/wwan/t7xx/t7xx_pci.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "t7xx_mhccif.h" #include "t7xx_modem_ops.h" @@ -44,6 +45,7 @@ #define T7XX_PCI_IREG_BASE 0 #define T7XX_PCI_EREG_BASE 2 +#define PM_SLEEP_DIS_TIMEOUT_MS 20 #define PM_ACK_TIMEOUT_MS 1500 #define PM_AUTOSUSPEND_MS 20000 #define PM_RESOURCE_POLL_TIMEOUT_US 10000 @@ -56,6 +58,21 @@ enum t7xx_pm_state { MTK_PM_RESUMED, }; +static void t7xx_dev_set_sleep_capability(struct t7xx_pci_dev *t7xx_dev, bool enable) +{ + void __iomem *ctrl_reg = IREG_BASE(t7xx_dev) + T7XX_PCIE_MISC_CTRL; + u32 value; + + value = ioread32(ctrl_reg); + + if (enable) + value &= ~T7XX_PCIE_MISC_MAC_SLEEP_DIS; + else + value |= T7XX_PCIE_MISC_MAC_SLEEP_DIS; + + iowrite32(value, ctrl_reg); +} + static int t7xx_wait_pm_config(struct t7xx_pci_dev *t7xx_dev) { int ret, val; @@ -76,6 +93,8 @@ static int t7xx_pci_pm_init(struct t7xx_pci_dev *t7xx_dev) INIT_LIST_HEAD(&t7xx_dev->md_pm_entities); mutex_init(&t7xx_dev->md_pm_entity_mtx); + spin_lock_init(&t7xx_dev->md_pm_lock); + init_completion(&t7xx_dev->sleep_lock_acquire); init_completion(&t7xx_dev->pm_sr_ack); atomic_set(&t7xx_dev->md_pm_state, MTK_PM_INIT); @@ -94,6 +113,7 @@ void t7xx_pci_pm_init_late(struct t7xx_pci_dev *t7xx_dev) { /* Enable the PCIe resource lock only after MD deep sleep is done */ t7xx_mhccif_mask_clr(t7xx_dev, + D2H_INT_DS_LOCK_ACK | D2H_INT_SUSPEND_ACK | D2H_INT_RESUME_ACK | D2H_INT_SUSPEND_ACK_AP | @@ -159,6 +179,79 @@ int t7xx_pci_pm_entity_unregister(struct t7xx_pci_dev *t7xx_dev, struct md_pm_en return -ENXIO; } +int t7xx_pci_sleep_disable_complete(struct t7xx_pci_dev *t7xx_dev) +{ + struct device *dev = &t7xx_dev->pdev->dev; + int ret; + + ret = wait_for_completion_timeout(&t7xx_dev->sleep_lock_acquire, + msecs_to_jiffies(PM_SLEEP_DIS_TIMEOUT_MS)); + if (!ret) + dev_err_ratelimited(dev, "Resource wait complete timed out\n"); + + return ret; +} + +/** + * t7xx_pci_disable_sleep() - Disable deep sleep capability. + * @t7xx_dev: MTK device. + * + * Lock the deep sleep capability, note that the device can still go into deep sleep + * state while device is in D0 state, from the host's point-of-view. + * + * If device is in deep sleep state, wake up the device and disable deep sleep capability. + */ +void t7xx_pci_disable_sleep(struct t7xx_pci_dev *t7xx_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&t7xx_dev->md_pm_lock, flags); + t7xx_dev->sleep_disable_count++; + if (atomic_read(&t7xx_dev->md_pm_state) < MTK_PM_RESUMED) + goto unlock_and_complete; + + if (t7xx_dev->sleep_disable_count == 1) { + u32 status; + + reinit_completion(&t7xx_dev->sleep_lock_acquire); + t7xx_dev_set_sleep_capability(t7xx_dev, false); + + status = ioread32(IREG_BASE(t7xx_dev) + T7XX_PCIE_RESOURCE_STATUS); + if (status & T7XX_PCIE_RESOURCE_STS_MSK) + goto unlock_and_complete; + + t7xx_mhccif_h2d_swint_trigger(t7xx_dev, H2D_CH_DS_LOCK); + } + spin_unlock_irqrestore(&t7xx_dev->md_pm_lock, flags); + return; + +unlock_and_complete: + spin_unlock_irqrestore(&t7xx_dev->md_pm_lock, flags); + complete_all(&t7xx_dev->sleep_lock_acquire); +} + +/** + * t7xx_pci_enable_sleep() - Enable deep sleep capability. + * @t7xx_dev: MTK device. + * + * After enabling deep sleep, device can enter into deep sleep state. + */ +void t7xx_pci_enable_sleep(struct t7xx_pci_dev *t7xx_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&t7xx_dev->md_pm_lock, flags); + t7xx_dev->sleep_disable_count--; + if (atomic_read(&t7xx_dev->md_pm_state) < MTK_PM_RESUMED) { + spin_unlock_irqrestore(&t7xx_dev->md_pm_lock, flags); + return; + } + + if (t7xx_dev->sleep_disable_count == 0) + t7xx_dev_set_sleep_capability(t7xx_dev, true); + spin_unlock_irqrestore(&t7xx_dev->md_pm_lock, flags); +} + static int t7xx_send_pm_request(struct t7xx_pci_dev *t7xx_dev, u32 request) { unsigned long wait_ret; diff --git a/drivers/net/wwan/t7xx/t7xx_pci.h b/drivers/net/wwan/t7xx/t7xx_pci.h index f51fc5a1301f..50b37056ce5a 100644 --- a/drivers/net/wwan/t7xx/t7xx_pci.h +++ b/drivers/net/wwan/t7xx/t7xx_pci.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "t7xx_reg.h" @@ -55,6 +56,9 @@ typedef irqreturn_t (*t7xx_intr_callback)(int irq, void *param); * @md_pm_entity_mtx: protects md_pm_entities list * @pm_sr_ack: ack from the device when went to sleep or woke up * @md_pm_state: state for resume/suspend + * @md_pm_lock: protects PCIe sleep lock + * @sleep_disable_count: PCIe L1.2 lock counter + * @sleep_lock_acquire: indicates that sleep has been disabled */ struct t7xx_pci_dev { t7xx_intr_callback intr_handler[EXT_INT_NUM]; @@ -71,6 +75,9 @@ struct t7xx_pci_dev { struct mutex md_pm_entity_mtx; /* Protects MD PM entities list */ struct completion pm_sr_ack; atomic_t md_pm_state; + spinlock_t md_pm_lock; /* Protects PCI resource lock */ + unsigned int sleep_disable_count; + struct completion sleep_lock_acquire; }; enum t7xx_pm_id { @@ -102,6 +109,9 @@ struct md_pm_entity { void *entity_param; }; +void t7xx_pci_disable_sleep(struct t7xx_pci_dev *t7xx_dev); +void t7xx_pci_enable_sleep(struct t7xx_pci_dev *t7xx_dev); +int t7xx_pci_sleep_disable_complete(struct t7xx_pci_dev *t7xx_dev); int t7xx_pci_pm_entity_register(struct t7xx_pci_dev *t7xx_dev, struct md_pm_entity *pm_entity); int t7xx_pci_pm_entity_unregister(struct t7xx_pci_dev *t7xx_dev, struct md_pm_entity *pm_entity); void t7xx_pci_pm_init_late(struct t7xx_pci_dev *t7xx_dev);