Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 31434512 authored by Veerabhadrarao Badiganti's avatar Veerabhadrarao Badiganti
Browse files

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: default avatarVeerabhadrarao Badiganti <vbadigan@codeaurora.org>
parent 86bc9bf1
Loading
Loading
Loading
Loading
+0 −1
Original line number Original line Diff line number Diff line
@@ -411,7 +411,6 @@ struct ep_pcie_dev_t {
	bool			     conf_ipa_msi_iatu;
	bool			     conf_ipa_msi_iatu;


	struct ep_pcie_register_event *event_reg;
	struct ep_pcie_register_event *event_reg;
	struct work_struct	     handle_perst_work;
	struct work_struct           handle_bme_work;
	struct work_struct           handle_bme_work;
	struct work_struct           handle_d3cold_work;
	struct work_struct           handle_d3cold_work;


+25 −17
Original line number Original line Diff line number Diff line
@@ -2354,18 +2354,6 @@ static int ep_pcie_enumeration(struct ep_pcie_dev_t *dev)
	return ret;
	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)
static void handle_d3cold_func(struct work_struct *work)
{
{
	struct ep_pcie_dev_t *dev = container_of(work, struct ep_pcie_dev_t,
	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;
	struct ep_pcie_dev_t *dev = data;
	unsigned long irqsave_flags;
	unsigned long irqsave_flags;
	irqreturn_t result = IRQ_HANDLED;
	u32 perst;
	u32 perst;


	spin_lock_irqsave(&dev->isr_lock, irqsave_flags);
	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",
					"PCIe V%d: Acquired wakelock\n",
					dev->rev);
					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 {
		} else {
			dev->no_notify = true;
			dev->no_notify = true;
			/* shutdown the link if the link is already on */
			/* 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,
		EP_PCIE_DBG(dev,
			"PCIe V%d: No. %ld PERST deassertion\n",
			"PCIe V%d: No. %ld PERST deassertion\n",
			dev->rev, dev->perst_deast_counter);
			dev->rev, dev->perst_deast_counter);
		ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_RST_DEAST);
		result = IRQ_WAKE_THREAD;
	} else {
	} else {
		atomic_set(&dev->perst_deast, 0);
		atomic_set(&dev->perst_deast, 0);
		dev->perst_ast_counter++;
		dev->perst_ast_counter++;
@@ -2480,6 +2472,22 @@ static irqreturn_t ep_pcie_handle_perst_irq(int irq, void *data)


	spin_unlock_irqrestore(&dev->isr_lock, irqsave_flags);
	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;
	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);
	EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);


	/* Initialize all works to be performed before registering for IRQs*/
	/* 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_bme_work, handle_bme_func);
	INIT_WORK(&dev->handle_d3cold_work, handle_d3cold_func);
	INIT_WORK(&dev->handle_d3cold_work, handle_d3cold_func);


@@ -2718,7 +2725,8 @@ int32_t ep_pcie_irq_init(struct ep_pcie_dev_t *dev)
	}
	}


	/* register handler for PERST interrupt */
	/* 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) ?
			       ((atomic_read(&dev->perst_deast) ?
				 IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH) |
				 IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH) |
			       IRQF_EARLY_RESUME), "ep_pcie_perst", dev);
			       IRQF_EARLY_RESUME), "ep_pcie_perst", dev);