mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-30 23:54:04 +08:00
net: wwan: t7xx: Fix Runtime PM resume sequence
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: 5545b7b9f2
("net: wwan: t7xx: Add NAPI support")
Signed-off-by: Kornel Dulęba <mindal@semihalf.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
60bd1d9008
commit
364d0221f1
@ -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]);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user