Merge branch 't7xx-pm-fixes'
Kornel Dulęba says:
====================
net: wwan: t7xx: Fix Runtime PM implementation
d10b3a695b ("net: wwan: t7xx: Runtime PM") introduced support for
Runtime PM for this driver, but due to a bug in the initialization logic
the usage refcount would never reach 0, leaving the feature unused.
This patchset addresses that, together with a bug found after runtime
suspend was enabled.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -152,6 +152,15 @@ static irqreturn_t t7xx_dpmaif_isr_handler(int irq, void *data)
|
||||
}
|
||||
|
||||
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_irq(struct dpmaif_ctrl *dpmaif_ctrl)
|
||||
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);
|
||||
|
||||
@@ -840,14 +840,13 @@ int t7xx_dpmaif_napi_rx_poll(struct napi_struct *napi, const int budget)
|
||||
|
||||
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_struct *napi, const int budget)
|
||||
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 dpmaif_ctrl *dpmaif_ctrl, const unsigned int
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -121,6 +121,8 @@ void t7xx_pci_pm_init_late(struct t7xx_pci_dev *t7xx_dev)
|
||||
iowrite32(T7XX_L1_BIT(0), IREG_BASE(t7xx_dev) + ENABLE_ASPM_LOWPWR);
|
||||
atomic_set(&t7xx_dev->md_pm_state, MTK_PM_RESUMED);
|
||||
|
||||
pm_runtime_mark_last_busy(&t7xx_dev->pdev->dev);
|
||||
pm_runtime_allow(&t7xx_dev->pdev->dev);
|
||||
pm_runtime_put_noidle(&t7xx_dev->pdev->dev);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user