From 31434512980aa3f9efd5eff735fd58aafb474f98 Mon Sep 17 00:00:00 2001 From: Veerabhadrarao Badiganti Date: Wed, 15 Sep 2021 23:07:03 +0530 Subject: [PATCH] msm: ep-pcie: Use threaded irq for PERST de-assertion handling When the host de-asserts the PERST, ep-pcie driver needs to bring-up the link as quickly as possible (within 150ms). Otherwise, the host may fail to detect the link. In our current design, we are doing the link initialization and link training in a kworker thread context. In some scenarios this context is incurring context switches and scheduling delays which is resulting in issues like the host fails to detect the link. To fix this, perform the link initialization and training in the highest possible priority (threaedIRQ). With this change, PCIe driver notifies clients in threadedIRQ context and the clients (Eg MHI) supposed to invoke the link training in the same context. Change-Id: I04de4a1dfb3a145b947a2824c6961da70215944b Signed-off-by: Veerabhadrarao Badiganti --- drivers/platform/msm/ep_pcie/ep_pcie_com.h | 1 - drivers/platform/msm/ep_pcie/ep_pcie_core.c | 42 ++++++++++++--------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h index bb5d581a8ba9..2090aa21755f 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h +++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h @@ -411,7 +411,6 @@ struct ep_pcie_dev_t { bool conf_ipa_msi_iatu; struct ep_pcie_register_event *event_reg; - struct work_struct handle_perst_work; struct work_struct handle_bme_work; struct work_struct handle_d3cold_work; diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c index 219e0e97b794..29efab766e3d 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c @@ -2354,18 +2354,6 @@ static int ep_pcie_enumeration(struct ep_pcie_dev_t *dev) return ret; } -static void handle_perst_func(struct work_struct *work) -{ - struct ep_pcie_dev_t *dev = container_of(work, struct ep_pcie_dev_t, - handle_perst_work); - - EP_PCIE_DBG(dev, - "PCIe V%d: Start enumeration due to PERST deassertion\n", - dev->rev); - - ep_pcie_enumeration(dev); -} - static void handle_d3cold_func(struct work_struct *work) { struct ep_pcie_dev_t *dev = container_of(work, struct ep_pcie_dev_t, @@ -2403,6 +2391,7 @@ static irqreturn_t ep_pcie_handle_perst_irq(int irq, void *data) { struct ep_pcie_dev_t *dev = data; unsigned long irqsave_flags; + irqreturn_t result = IRQ_HANDLED; u32 perst; spin_lock_irqsave(&dev->isr_lock, irqsave_flags); @@ -2427,8 +2416,11 @@ static irqreturn_t ep_pcie_handle_perst_irq(int irq, void *data) "PCIe V%d: Acquired wakelock\n", dev->rev); } - /* start work for link enumeration with the host side */ - queue_work(system_highpri_wq, &dev->handle_perst_work); + /* + * Perform link enumeration with the host side in the + * bottom half + */ + result = IRQ_WAKE_THREAD; } else { dev->no_notify = true; /* shutdown the link if the link is already on */ @@ -2454,7 +2446,7 @@ static irqreturn_t ep_pcie_handle_perst_irq(int irq, void *data) EP_PCIE_DBG(dev, "PCIe V%d: No. %ld PERST deassertion\n", dev->rev, dev->perst_deast_counter); - ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_RST_DEAST); + result = IRQ_WAKE_THREAD; } else { atomic_set(&dev->perst_deast, 0); dev->perst_ast_counter++; @@ -2480,6 +2472,22 @@ out: spin_unlock_irqrestore(&dev->isr_lock, irqsave_flags); + return result; +} + +static irqreturn_t ep_pcie_handle_perst_deassert(int irq, void *data) +{ + struct ep_pcie_dev_t *dev = data; + + if (!dev->enumerated) { + EP_PCIE_DBG(dev, + "PCIe V%d: Start enumeration due to PERST deassertion\n", + dev->rev); + ep_pcie_enumeration(dev); + } else { + ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_RST_DEAST); + } + return IRQ_HANDLED; } @@ -2598,7 +2606,6 @@ int32_t ep_pcie_irq_init(struct ep_pcie_dev_t *dev) EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev); /* Initialize all works to be performed before registering for IRQs*/ - INIT_WORK(&dev->handle_perst_work, handle_perst_func); INIT_WORK(&dev->handle_bme_work, handle_bme_func); INIT_WORK(&dev->handle_d3cold_work, handle_d3cold_func); @@ -2718,7 +2725,8 @@ perst_irq: } /* register handler for PERST interrupt */ - ret = devm_request_irq(pdev, dev->perst_irq, ep_pcie_handle_perst_irq, + ret = devm_request_threaded_irq(pdev, dev->perst_irq, ep_pcie_handle_perst_irq, + ep_pcie_handle_perst_deassert, ((atomic_read(&dev->perst_deast) ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH) | IRQF_EARLY_RESUME), "ep_pcie_perst", dev);