155 lines
5.0 KiB
Diff
155 lines
5.0 KiB
Diff
|
|
From 364d0221f1788e5225006ba7a0026e5968431c29 Mon Sep 17 00:00:00 2001
|
||
|
|
From: =?UTF-8?q?Kornel=20Dul=C4=99ba?= <mindal@semihalf.com>
|
||
|
|
Date: Thu, 26 Jan 2023 13:25:34 +0000
|
||
|
|
Subject: [PATCH] net: wwan: t7xx: Fix Runtime PM resume sequence
|
||
|
|
MIME-Version: 1.0
|
||
|
|
Content-Type: text/plain; charset=UTF-8
|
||
|
|
Content-Transfer-Encoding: 8bit
|
||
|
|
|
||
|
|
Resume device before calling napi_schedule, instead of doing in the napi
|
||
|
|
poll routine. Polling is done in softrq context. We can't call the PM
|
||
|
|
resume logic from there as it's blocking and not irq safe.
|
||
|
|
In order to make it work modify the interrupt handler to be run from irq
|
||
|
|
handler thread.
|
||
|
|
|
||
|
|
Fixes: 5545b7b9f294 ("net: wwan: t7xx: Add NAPI support")
|
||
|
|
Signed-off-by: Kornel Dulęba <mindal@semihalf.com>
|
||
|
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||
|
|
---
|
||
|
|
drivers/net/wwan/t7xx/t7xx_hif_dpmaif.c | 11 +++++++-
|
||
|
|
drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c | 29 +++++++++++++++-------
|
||
|
|
drivers/net/wwan/t7xx/t7xx_netdev.c | 16 +++++++++++-
|
||
|
|
3 files changed, 45 insertions(+), 11 deletions(-)
|
||
|
|
|
||
|
|
--- a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif.c
|
||
|
|
+++ b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif.c
|
||
|
|
@@ -152,6 +152,15 @@ static irqreturn_t t7xx_dpmaif_isr_handl
|
||
|
|
}
|
||
|
|
|
||
|
|
t7xx_pcie_mac_clear_int(dpmaif_ctrl->t7xx_dev, isr_para->pcie_int);
|
||
|
|
+
|
||
|
|
+ return IRQ_WAKE_THREAD;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static irqreturn_t t7xx_dpmaif_isr_thread(int irq, void *data)
|
||
|
|
+{
|
||
|
|
+ struct dpmaif_isr_para *isr_para = data;
|
||
|
|
+ struct dpmaif_ctrl *dpmaif_ctrl = isr_para->dpmaif_ctrl;
|
||
|
|
+
|
||
|
|
t7xx_dpmaif_irq_cb(isr_para);
|
||
|
|
t7xx_pcie_mac_set_int(dpmaif_ctrl->t7xx_dev, isr_para->pcie_int);
|
||
|
|
return IRQ_HANDLED;
|
||
|
|
@@ -188,7 +197,7 @@ static void t7xx_dpmaif_register_pcie_ir
|
||
|
|
t7xx_pcie_mac_clear_int(t7xx_dev, int_type);
|
||
|
|
|
||
|
|
t7xx_dev->intr_handler[int_type] = t7xx_dpmaif_isr_handler;
|
||
|
|
- t7xx_dev->intr_thread[int_type] = NULL;
|
||
|
|
+ t7xx_dev->intr_thread[int_type] = t7xx_dpmaif_isr_thread;
|
||
|
|
t7xx_dev->callback_param[int_type] = isr_para;
|
||
|
|
|
||
|
|
t7xx_pcie_mac_clear_int_status(t7xx_dev, int_type);
|
||
|
|
--- a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c
|
||
|
|
+++ b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c
|
||
|
|
@@ -840,14 +840,13 @@ int t7xx_dpmaif_napi_rx_poll(struct napi
|
||
|
|
|
||
|
|
if (!rxq->que_started) {
|
||
|
|
atomic_set(&rxq->rx_processing, 0);
|
||
|
|
+ pm_runtime_put_autosuspend(rxq->dpmaif_ctrl->dev);
|
||
|
|
dev_err(rxq->dpmaif_ctrl->dev, "Work RXQ: %d has not been started\n", rxq->index);
|
||
|
|
return work_done;
|
||
|
|
}
|
||
|
|
|
||
|
|
- if (!rxq->sleep_lock_pending) {
|
||
|
|
- pm_runtime_get_noresume(rxq->dpmaif_ctrl->dev);
|
||
|
|
+ if (!rxq->sleep_lock_pending)
|
||
|
|
t7xx_pci_disable_sleep(t7xx_dev);
|
||
|
|
- }
|
||
|
|
|
||
|
|
ret = try_wait_for_completion(&t7xx_dev->sleep_lock_acquire);
|
||
|
|
if (!ret) {
|
||
|
|
@@ -876,22 +875,22 @@ int t7xx_dpmaif_napi_rx_poll(struct napi
|
||
|
|
napi_complete_done(napi, work_done);
|
||
|
|
t7xx_dpmaif_clr_ip_busy_sts(&rxq->dpmaif_ctrl->hw_info);
|
||
|
|
t7xx_dpmaif_dlq_unmask_rx_done(&rxq->dpmaif_ctrl->hw_info, rxq->index);
|
||
|
|
+ t7xx_pci_enable_sleep(rxq->dpmaif_ctrl->t7xx_dev);
|
||
|
|
+ pm_runtime_mark_last_busy(rxq->dpmaif_ctrl->dev);
|
||
|
|
+ pm_runtime_put_autosuspend(rxq->dpmaif_ctrl->dev);
|
||
|
|
+ atomic_set(&rxq->rx_processing, 0);
|
||
|
|
} else {
|
||
|
|
t7xx_dpmaif_clr_ip_busy_sts(&rxq->dpmaif_ctrl->hw_info);
|
||
|
|
}
|
||
|
|
|
||
|
|
- t7xx_pci_enable_sleep(rxq->dpmaif_ctrl->t7xx_dev);
|
||
|
|
- pm_runtime_mark_last_busy(rxq->dpmaif_ctrl->dev);
|
||
|
|
- pm_runtime_put_noidle(rxq->dpmaif_ctrl->dev);
|
||
|
|
- atomic_set(&rxq->rx_processing, 0);
|
||
|
|
-
|
||
|
|
return work_done;
|
||
|
|
}
|
||
|
|
|
||
|
|
void t7xx_dpmaif_irq_rx_done(struct dpmaif_ctrl *dpmaif_ctrl, const unsigned int que_mask)
|
||
|
|
{
|
||
|
|
struct dpmaif_rx_queue *rxq;
|
||
|
|
- int qno;
|
||
|
|
+ struct dpmaif_ctrl *ctrl;
|
||
|
|
+ int qno, ret;
|
||
|
|
|
||
|
|
qno = ffs(que_mask) - 1;
|
||
|
|
if (qno < 0 || qno > DPMAIF_RXQ_NUM - 1) {
|
||
|
|
@@ -900,6 +899,18 @@ void t7xx_dpmaif_irq_rx_done(struct dpma
|
||
|
|
}
|
||
|
|
|
||
|
|
rxq = &dpmaif_ctrl->rxq[qno];
|
||
|
|
+ ctrl = rxq->dpmaif_ctrl;
|
||
|
|
+ /* We need to make sure that the modem has been resumed before
|
||
|
|
+ * calling napi. This can't be done inside the polling function
|
||
|
|
+ * as we could be blocked waiting for device to be resumed,
|
||
|
|
+ * which can't be done from softirq context the poll function
|
||
|
|
+ * is running in.
|
||
|
|
+ */
|
||
|
|
+ ret = pm_runtime_resume_and_get(ctrl->dev);
|
||
|
|
+ if (ret < 0 && ret != -EACCES) {
|
||
|
|
+ dev_err(ctrl->dev, "Failed to resume device: %d\n", ret);
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
napi_schedule(&rxq->napi);
|
||
|
|
}
|
||
|
|
|
||
|
|
--- a/drivers/net/wwan/t7xx/t7xx_netdev.c
|
||
|
|
+++ b/drivers/net/wwan/t7xx/t7xx_netdev.c
|
||
|
|
@@ -27,6 +27,7 @@
|
||
|
|
#include <linux/list.h>
|
||
|
|
#include <linux/netdev_features.h>
|
||
|
|
#include <linux/netdevice.h>
|
||
|
|
+#include <linux/pm_runtime.h>
|
||
|
|
#include <linux/skbuff.h>
|
||
|
|
#include <linux/types.h>
|
||
|
|
#include <linux/wwan.h>
|
||
|
|
@@ -45,12 +46,25 @@
|
||
|
|
|
||
|
|
static void t7xx_ccmni_enable_napi(struct t7xx_ccmni_ctrl *ctlb)
|
||
|
|
{
|
||
|
|
- int i;
|
||
|
|
+ struct dpmaif_ctrl *ctrl;
|
||
|
|
+ int i, ret;
|
||
|
|
+
|
||
|
|
+ ctrl = ctlb->hif_ctrl;
|
||
|
|
|
||
|
|
if (ctlb->is_napi_en)
|
||
|
|
return;
|
||
|
|
|
||
|
|
for (i = 0; i < RXQ_NUM; i++) {
|
||
|
|
+ /* The usage count has to be bumped every time before calling
|
||
|
|
+ * napi_schedule. It will be decresed in the poll routine,
|
||
|
|
+ * right after napi_complete_done is called.
|
||
|
|
+ */
|
||
|
|
+ ret = pm_runtime_resume_and_get(ctrl->dev);
|
||
|
|
+ if (ret < 0) {
|
||
|
|
+ dev_err(ctrl->dev, "Failed to resume device: %d\n",
|
||
|
|
+ ret);
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
napi_enable(ctlb->napi[i]);
|
||
|
|
napi_schedule(ctlb->napi[i]);
|
||
|
|
}
|