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

Commit 08169898 authored by Yan He's avatar Yan He
Browse files

msm: ep_pcie: add the support of D3 cold before BME is set



Host side could turn off PCIe link before BME is set or before PCIe
client is notified that link is enabled. Add the support here to
handle the D3 cold in those situations.

Change-Id: I2cbc30fca6a40375094c116662d421505cc8a140
Signed-off-by: default avatarYan He <yanhe@codeaurora.org>
parent 50222ad7
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -340,10 +340,13 @@ struct ep_pcie_dev_t {
	bool                         l23_ready;
	bool                         l23_ready;
	bool                         l1ss_enabled;
	bool                         l1ss_enabled;
	struct ep_pcie_msi_config    msi_cfg;
	struct ep_pcie_msi_config    msi_cfg;
	bool                         no_notify;
	bool                         client_ready;


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


extern struct ep_pcie_dev_t ep_pcie_dev;
extern struct ep_pcie_dev_t ep_pcie_dev;
+62 −7
Original line number Original line Diff line number Diff line
@@ -1060,6 +1060,10 @@ static void ep_pcie_release_resources(struct ep_pcie_dev_t *dev)


static void ep_pcie_enumeration_complete(struct ep_pcie_dev_t *dev)
static void ep_pcie_enumeration_complete(struct ep_pcie_dev_t *dev)
{
{
	unsigned long irqsave_flags;

	spin_lock_irqsave(&dev->isr_lock, irqsave_flags);

	dev->enumerated = true;
	dev->enumerated = true;
	dev->link_status = EP_PCIE_LINK_ENABLED;
	dev->link_status = EP_PCIE_LINK_ENABLED;


@@ -1086,7 +1090,14 @@ static void ep_pcie_enumeration_complete(struct ep_pcie_dev_t *dev)
		"PCIe V%d: register driver for device 0x%x.\n",
		"PCIe V%d: register driver for device 0x%x.\n",
		ep_pcie_dev.rev, hw_drv.device_id);
		ep_pcie_dev.rev, hw_drv.device_id);
	ep_pcie_register_drv(&hw_drv);
	ep_pcie_register_drv(&hw_drv);
	if (!dev->no_notify)
		ep_pcie_notify_event(dev, EP_PCIE_EVENT_LINKUP);
		ep_pcie_notify_event(dev, EP_PCIE_EVENT_LINKUP);
	else
		EP_PCIE_DBG(dev,
			"PCIe V%d: do not notify client about linkup.\n",
			dev->rev);

	spin_unlock_irqrestore(&dev->isr_lock, irqsave_flags);
}
}


int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt)
int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt)
@@ -1584,7 +1595,13 @@ static irqreturn_t ep_pcie_handle_dstate_change_irq(int irq, void *data)
			"PCIe V%d: No. %ld change to D3 state.\n",
			"PCIe V%d: No. %ld change to D3 state.\n",
			dev->rev, dev->d3_counter);
			dev->rev, dev->d3_counter);
		ep_pcie_write_mask(dev->parf + PCIE20_PARF_PM_CTRL, 0, BIT(1));
		ep_pcie_write_mask(dev->parf + PCIE20_PARF_PM_CTRL, 0, BIT(1));

		if (dev->enumerated)
			ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_D3_HOT);
			ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_D3_HOT);
		else
			EP_PCIE_DBG(dev,
				"PCIe V%d: do not notify client about this D3 hot event since enumeration by HLOS is not done yet.\n",
				dev->rev);
	} else if (dstate == 0) {
	} else if (dstate == 0) {
		dev->l23_ready = false;
		dev->l23_ready = false;
		dev->d0_counter++;
		dev->d0_counter++;
@@ -1648,9 +1665,25 @@ static void handle_perst_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,
					handle_perst_work);
					handle_perst_work);


	EP_PCIE_DBG(dev,
		"PCIe V%d: Start enumeration due to PERST deassertion.\n",
		dev->rev);

	ep_pcie_enumeration(dev);
	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,
					handle_d3cold_work);

	EP_PCIE_DBG(dev,
		"PCIe V%d: shutdown PCIe link due to PERST assertion before BME is set.\n",
		dev->rev);
	ep_pcie_core_disable_endpoint();
	dev->no_notify = false;
}

static void handle_bme_func(struct work_struct *work)
static void handle_bme_func(struct work_struct *work)
{
{
	struct ep_pcie_dev_t *dev = container_of(work,
	struct ep_pcie_dev_t *dev = container_of(work,
@@ -1673,10 +1706,14 @@ static irqreturn_t ep_pcie_handle_perst_irq(int irq, void *data)
		EP_PCIE_DBG(dev,
		EP_PCIE_DBG(dev,
			"PCIe V%d: PCIe is not enumerated yet; PERST is %sasserted.\n",
			"PCIe V%d: PCIe is not enumerated yet; PERST is %sasserted.\n",
			dev->rev, perst ? "de" : "");
			dev->rev, perst ? "de" : "");
		if ((!dev->perst_enum) || !perst)
		if (perst) {
			goto out;
			/* start work for link enumeration with the host side */
			/* start work for link enumeration with the host side */
			schedule_work(&dev->handle_perst_work);
			schedule_work(&dev->handle_perst_work);
		} else {
			dev->no_notify = true;
			/* shutdown the link if the link is already on */
			schedule_work(&dev->handle_d3cold_work);
		}


		goto out;
		goto out;
	}
	}
@@ -1694,7 +1731,16 @@ 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 assertion.\n",
			"PCIe V%d: No. %ld PERST assertion.\n",
			dev->rev, dev->perst_ast_counter);
			dev->rev, dev->perst_ast_counter);

		if (dev->client_ready) {
			ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_D3_COLD);
			ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_D3_COLD);
		} else {
			dev->no_notify = true;
			EP_PCIE_DBG(dev,
				"PCIe V%d: Client driver is not ready when this PERST assertion happens; shutdown link now.\n",
				dev->rev);
			schedule_work(&dev->handle_d3cold_work);
		}
	}
	}


out:
out:
@@ -1779,6 +1825,7 @@ int32_t ep_pcie_irq_init(struct ep_pcie_dev_t *dev)
	/* 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_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);


	if (dev->aggregated_irq) {
	if (dev->aggregated_irq) {
		ret = devm_request_irq(pdev,
		ret = devm_request_irq(pdev,
@@ -1932,6 +1979,8 @@ int ep_pcie_core_register_event(struct ep_pcie_register_event *reg)
		"PCIe V%d: Event 0x%x is registered\n",
		"PCIe V%d: Event 0x%x is registered\n",
		ep_pcie_dev.rev, reg->events);
		ep_pcie_dev.rev, reg->events);


	ep_pcie_dev.client_ready = true;

	return 0;
	return 0;
}
}


@@ -1970,6 +2019,12 @@ enum ep_pcie_link_status ep_pcie_core_get_linkstatus(void)
			"PCIe V%d: PCIe link is up and BME is enabled; current SW link status:%d.\n",
			"PCIe V%d: PCIe link is up and BME is enabled; current SW link status:%d.\n",
			dev->rev, dev->link_status);
			dev->rev, dev->link_status);
		dev->link_status = EP_PCIE_LINK_ENABLED;
		dev->link_status = EP_PCIE_LINK_ENABLED;
		if (dev->no_notify) {
			EP_PCIE_DBG(dev,
				"PCIe V%d: BME is set now, but do not tell client about BME enable.\n",
				dev->rev);
			return EP_PCIE_LINK_UP;
		}
	} else {
	} else {
		EP_PCIE_DBG(dev,
		EP_PCIE_DBG(dev,
			"PCIe V%d: PCIe link is up but BME is disabled; current SW link status:%d.\n",
			"PCIe V%d: PCIe link is up but BME is disabled; current SW link status:%d.\n",