Unverified Commit 473b2cf9 authored by Manivannan Sadhasivam's avatar Manivannan Sadhasivam Committed by Krzysztof Wilczyński
Browse files

PCI: endpoint: Introduce 'epc_deinit' event and notify the EPF drivers

As like the 'epc_init' event, that is used to signal the EPF drivers about
the EPC initialization, let's introduce 'epc_deinit' event that is used to
signal EPC deinitialization.

The EPC deinitialization applies only when any sort of fundamental reset
is supported by the endpoint controller as per the PCIe spec.

Reference: PCIe r6.0, sec 4.2.5.9.1 and 6.6.1.

Currently, some EPC drivers like pcie-qcom-ep and pcie-tegra194 support
PERST# as the fundamental reset. So the 'deinit' event will be notified to
the EPF drivers when PERST# assert happens in the above mentioned EPC
drivers.

The EPF drivers, on receiving the event through the epc_deinit() callback
should reset the EPF state machine and also cleanup any configuration that
got affected by the fundamental reset like BAR, DMA etc...

This change also warrants skipping the cleanups in unbind() if already done
in epc_deinit().

Link: https://lore.kernel.org/r/20240606-pci-deinit-v1-2-4395534520dc@linaro.org


Signed-off-by: default avatarManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: default avatarKrzysztof Wilczyński <kwilczynski@kernel.org>
Reviewed-by: default avatarNiklas Cassel <cassel@kernel.org>
Reviewed-by: default avatarSiddharth Vadapalli <s-vadapalli@ti.com>
Reviewed-by: default avatarFrank Li <Frank.Li@nxp.com>
parent cfc2d4c5
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -632,7 +632,6 @@ void dw_pcie_ep_cleanup(struct dw_pcie_ep *ep)
	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);

	dw_pcie_edma_remove(pci);
	ep->epc->init_complete = false;
}
EXPORT_SYMBOL_GPL(dw_pcie_ep_cleanup);

+1 −0
Original line number Diff line number Diff line
@@ -507,6 +507,7 @@ static void qcom_pcie_perst_assert(struct dw_pcie *pci)
		return;
	}

	pci_epc_deinit_notify(pci->ep.epc);
	dw_pcie_ep_cleanup(&pci->ep);
	qcom_pcie_disable_resources(pcie_ep);
	pcie_ep->link_status = QCOM_PCIE_EP_LINK_DISABLED;
+1 −0
Original line number Diff line number Diff line
@@ -1715,6 +1715,7 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie)
	if (ret)
		dev_err(pcie->dev, "Failed to go Detect state: %d\n", ret);

	pci_epc_deinit_notify(pcie->pci.ep.epc);
	dw_pcie_ep_cleanup(&pcie->pci.ep);

	reset_control_assert(pcie->core_rst);
+19 −0
Original line number Diff line number Diff line
@@ -764,6 +764,24 @@ static int pci_epf_mhi_epc_init(struct pci_epf *epf)
	return 0;
}

static void pci_epf_mhi_epc_deinit(struct pci_epf *epf)
{
	struct pci_epf_mhi *epf_mhi = epf_get_drvdata(epf);
	const struct pci_epf_mhi_ep_info *info = epf_mhi->info;
	struct pci_epf_bar *epf_bar = &epf->bar[info->bar_num];
	struct mhi_ep_cntrl *mhi_cntrl = &epf_mhi->mhi_cntrl;
	struct pci_epc *epc = epf->epc;

	if (mhi_cntrl->mhi_dev) {
		mhi_ep_power_down(mhi_cntrl);
		if (info->flags & MHI_EPF_USE_DMA)
			pci_epf_mhi_dma_deinit(epf_mhi);
		mhi_ep_unregister_controller(mhi_cntrl);
	}

	pci_epc_clear_bar(epc, epf->func_no, epf->vfunc_no, epf_bar);
}

static int pci_epf_mhi_link_up(struct pci_epf *epf)
{
	struct pci_epf_mhi *epf_mhi = epf_get_drvdata(epf);
@@ -898,6 +916,7 @@ static void pci_epf_mhi_unbind(struct pci_epf *epf)

static const struct pci_epc_event_ops pci_epf_mhi_event_ops = {
	.epc_init = pci_epf_mhi_epc_init,
	.epc_deinit = pci_epf_mhi_epc_deinit,
	.link_up = pci_epf_mhi_link_up,
	.link_down = pci_epf_mhi_link_down,
	.bus_master_enable = pci_epf_mhi_bus_master_enable,
+15 −2
Original line number Diff line number Diff line
@@ -782,6 +782,15 @@ static int pci_epf_test_epc_init(struct pci_epf *epf)
	return 0;
}

static void pci_epf_test_epc_deinit(struct pci_epf *epf)
{
	struct pci_epf_test *epf_test = epf_get_drvdata(epf);

	cancel_delayed_work(&epf_test->cmd_handler);
	pci_epf_test_clean_dma_chan(epf_test);
	pci_epf_test_clear_bar(epf);
}

static int pci_epf_test_link_up(struct pci_epf *epf)
{
	struct pci_epf_test *epf_test = epf_get_drvdata(epf);
@@ -803,6 +812,7 @@ static int pci_epf_test_link_down(struct pci_epf *epf)

static const struct pci_epc_event_ops pci_epf_test_event_ops = {
	.epc_init = pci_epf_test_epc_init,
	.epc_deinit = pci_epf_test_epc_deinit,
	.link_up = pci_epf_test_link_up,
	.link_down = pci_epf_test_link_down,
};
@@ -905,10 +915,13 @@ static int pci_epf_test_bind(struct pci_epf *epf)
static void pci_epf_test_unbind(struct pci_epf *epf)
{
	struct pci_epf_test *epf_test = epf_get_drvdata(epf);
	struct pci_epc *epc = epf->epc;

	cancel_delayed_work(&epf_test->cmd_handler);
	if (epc->init_complete) {
		pci_epf_test_clean_dma_chan(epf_test);
		pci_epf_test_clear_bar(epf);
	}
	pci_epf_test_free_space(epf);
}

Loading