Re: [PATCH v12 8/8] PCI: endpoint: Remove "core_init_notifier" flag
From: Frank Li
Date: Fri Mar 29 2024 - 15:18:14 EST
On Wed, Mar 27, 2024 at 02:43:37PM +0530, Manivannan Sadhasivam wrote:
> "core_init_notifier" flag is set by the glue drivers requiring refclk from
> the host to complete the DWC core initialization. Also, those drivers will
> send a notification to the EPF drivers once the initialization is fully
> completed using the pci_epc_init_notify() API. Only then, the EPF drivers
> will start functioning.
>
> For the rest of the drivers generating refclk locally, EPF drivers will
> start functioning post binding with them. EPF drivers rely on the
> 'core_init_notifier' flag to differentiate between the drivers.
> Unfortunately, this creates two different flows for the EPF drivers.
>
> So to avoid that, let's get rid of the "core_init_notifier" flag and follow
> a single initialization flow for the EPF drivers. This is done by calling
> the dw_pcie_ep_init_notify() from all glue drivers after the completion of
> dw_pcie_ep_init_registers() API. This will allow all the glue drivers to
> send the notification to the EPF drivers once the initialization is fully
> completed.
>
> Only difference here is that, the drivers requiring refclk from host will
> send the notification once refclk is received, while others will send it
> during probe time itself.
>
> But this also requires the EPC core driver to deliver the notification
> after EPF driver bind. Because, the glue driver can send the notification
> before the EPF drivers bind() and in those cases the EPF drivers will miss
> the event. To accommodate this, EPC core is now caching the state of the
> EPC initialization in 'init_complete' flag and pci-ep-cfs driver sends the
> notification to EPF drivers based on that after each EPF driver bind.
>
> Tested-by: Niklas Cassel <cassel@xxxxxxxxxx>
Reviewed-by: Frank Li <Frank.Li@xxxxxxx>
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@xxxxxxxxxx>
> ---
> drivers/pci/controller/cadence/pcie-cadence-ep.c | 2 ++
> drivers/pci/controller/dwc/pci-dra7xx.c | 2 ++
> drivers/pci/controller/dwc/pci-imx6.c | 2 ++
> drivers/pci/controller/dwc/pci-keystone.c | 2 ++
> drivers/pci/controller/dwc/pci-layerscape-ep.c | 2 ++
> drivers/pci/controller/dwc/pcie-artpec6.c | 2 ++
> drivers/pci/controller/dwc/pcie-designware-ep.c | 1 +
> drivers/pci/controller/dwc/pcie-designware-plat.c | 2 ++
> drivers/pci/controller/dwc/pcie-keembay.c | 2 ++
> drivers/pci/controller/dwc/pcie-qcom-ep.c | 1 -
> drivers/pci/controller/dwc/pcie-rcar-gen4.c | 2 ++
> drivers/pci/controller/dwc/pcie-tegra194.c | 1 -
> drivers/pci/controller/dwc/pcie-uniphier-ep.c | 2 ++
> drivers/pci/controller/pcie-rcar-ep.c | 2 ++
> drivers/pci/controller/pcie-rockchip-ep.c | 2 ++
> drivers/pci/endpoint/functions/pci-epf-test.c | 18 +++++-------------
> drivers/pci/endpoint/pci-ep-cfs.c | 9 +++++++++
> drivers/pci/endpoint/pci-epc-core.c | 22 ++++++++++++++++++++++
> include/linux/pci-epc.h | 7 ++++---
> 19 files changed, 65 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
> index 81c50dc64da9..55c42ca2b777 100644
> --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
> +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
> @@ -746,6 +746,8 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
>
> spin_lock_init(&ep->lock);
>
> + pci_epc_init_notify(epc);
> +
> return 0;
>
> free_epc_mem:
> diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c
> index 395042b29ffc..d2d17d37d3e0 100644
> --- a/drivers/pci/controller/dwc/pci-dra7xx.c
> +++ b/drivers/pci/controller/dwc/pci-dra7xx.c
> @@ -474,6 +474,8 @@ static int dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx,
> return ret;
> }
>
> + dw_pcie_ep_init_notify(ep);
> +
> return 0;
> }
>
> diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
> index 8d28ecc381bc..917c69edee1d 100644
> --- a/drivers/pci/controller/dwc/pci-imx6.c
> +++ b/drivers/pci/controller/dwc/pci-imx6.c
> @@ -1131,6 +1131,8 @@ static int imx6_add_pcie_ep(struct imx6_pcie *imx6_pcie,
> return ret;
> }
>
> + dw_pcie_ep_init_notify(ep);
> +
> /* Start LTSSM. */
> imx6_pcie_ltssm_enable(dev);
>
> diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
> index 81ebac520650..d3a7d14ee685 100644
> --- a/drivers/pci/controller/dwc/pci-keystone.c
> +++ b/drivers/pci/controller/dwc/pci-keystone.c
> @@ -1293,6 +1293,8 @@ static int ks_pcie_probe(struct platform_device *pdev)
> goto err_ep_init;
> }
>
> + dw_pcie_ep_init_notify(&pci->ep);
> +
> break;
> default:
> dev_err(dev, "INVALID device type %d\n", mode);
> diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c
> index 9eb2233e3d7f..7dde6d5fa4d8 100644
> --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c
> +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c
> @@ -286,6 +286,8 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
> return ret;
> }
>
> + dw_pcie_ep_init_notify(&pci->ep);
> +
> return ls_pcie_ep_interrupt_init(pcie, pdev);
> }
>
> diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c
> index a6095561db4a..a4630b92489b 100644
> --- a/drivers/pci/controller/dwc/pcie-artpec6.c
> +++ b/drivers/pci/controller/dwc/pcie-artpec6.c
> @@ -452,6 +452,8 @@ static int artpec6_pcie_probe(struct platform_device *pdev)
> return ret;
> }
>
> + dw_pcie_ep_init_notify(&pci->ep);
> +
> break;
> default:
> dev_err(dev, "INVALID device type %d\n", artpec6_pcie->mode);
> diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> index 2063cf2049e5..47391d7d3a73 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> @@ -632,6 +632,7 @@ 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);
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
> index ca9b22e654cd..8490c5d6ff9f 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-plat.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
> @@ -154,6 +154,8 @@ static int dw_plat_pcie_probe(struct platform_device *pdev)
> dw_pcie_ep_deinit(&pci->ep);
> }
>
> + dw_pcie_ep_init_notify(&pci->ep);
> +
> break;
> default:
> dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode);
> diff --git a/drivers/pci/controller/dwc/pcie-keembay.c b/drivers/pci/controller/dwc/pcie-keembay.c
> index b2556dbcffb5..98bbc83182b4 100644
> --- a/drivers/pci/controller/dwc/pcie-keembay.c
> +++ b/drivers/pci/controller/dwc/pcie-keembay.c
> @@ -442,6 +442,8 @@ static int keembay_pcie_probe(struct platform_device *pdev)
> return ret;
> }
>
> + dw_pcie_ep_init_notify(&pci->ep);
> +
> break;
> default:
> dev_err(dev, "Invalid device type %d\n", pcie->mode);
> diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c
> index 3697b4a944cc..2fb8c15e7a91 100644
> --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c
> +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c
> @@ -775,7 +775,6 @@ static void qcom_pcie_ep_init_debugfs(struct qcom_pcie_ep *pcie_ep)
>
> static const struct pci_epc_features qcom_pcie_epc_features = {
> .linkup_notifier = true,
> - .core_init_notifier = true,
> .msi_capable = true,
> .msix_capable = false,
> .align = SZ_4K,
> diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> index e155a905fb4f..cfeccc2f9ee1 100644
> --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> @@ -437,6 +437,8 @@ static int rcar_gen4_add_dw_pcie_ep(struct rcar_gen4_pcie *rcar)
> rcar_gen4_pcie_ep_deinit(rcar);
> }
>
> + dw_pcie_ep_init_notify(ep);
> +
> return ret;
> }
>
> diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
> index db043f579fbe..ddc23602eca7 100644
> --- a/drivers/pci/controller/dwc/pcie-tegra194.c
> +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
> @@ -2006,7 +2006,6 @@ static int tegra_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
>
> static const struct pci_epc_features tegra_pcie_epc_features = {
> .linkup_notifier = true,
> - .core_init_notifier = true,
> .msi_capable = false,
> .msix_capable = false,
> .bar[BAR_0] = { .type = BAR_FIXED, .fixed_size = SZ_1M,
> diff --git a/drivers/pci/controller/dwc/pcie-uniphier-ep.c b/drivers/pci/controller/dwc/pcie-uniphier-ep.c
> index 0e5e7344de48..a2b844268e28 100644
> --- a/drivers/pci/controller/dwc/pcie-uniphier-ep.c
> +++ b/drivers/pci/controller/dwc/pcie-uniphier-ep.c
> @@ -410,6 +410,8 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev)
> return ret;
> }
>
> + dw_pcie_ep_init_notify(&priv->pci.ep);
> +
> return 0;
> }
>
> diff --git a/drivers/pci/controller/pcie-rcar-ep.c b/drivers/pci/controller/pcie-rcar-ep.c
> index 05967c6c0b42..047e2cef5afc 100644
> --- a/drivers/pci/controller/pcie-rcar-ep.c
> +++ b/drivers/pci/controller/pcie-rcar-ep.c
> @@ -542,6 +542,8 @@ static int rcar_pcie_ep_probe(struct platform_device *pdev)
> goto err_pm_put;
> }
>
> + pci_epc_init_notify(epc);
> +
> return 0;
>
> err_pm_put:
> diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
> index c9046e97a1d2..8613df8184df 100644
> --- a/drivers/pci/controller/pcie-rockchip-ep.c
> +++ b/drivers/pci/controller/pcie-rockchip-ep.c
> @@ -609,6 +609,8 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev)
> rockchip_pcie_write(rockchip, PCIE_CLIENT_CONF_ENABLE,
> PCIE_CLIENT_CONFIG);
>
> + pci_epc_init_notify(epc);
> +
> return 0;
> err_epc_mem_exit:
> pci_epc_mem_exit(epc);
> diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
> index cd4ffb39dcdc..212fc303fb63 100644
> --- a/drivers/pci/endpoint/functions/pci-epf-test.c
> +++ b/drivers/pci/endpoint/functions/pci-epf-test.c
> @@ -753,6 +753,7 @@ static int pci_epf_test_core_init(struct pci_epf *epf)
> const struct pci_epc_features *epc_features;
> struct pci_epc *epc = epf->epc;
> struct device *dev = &epf->dev;
> + bool linkup_notifier = false;
> bool msix_capable = false;
> bool msi_capable = true;
> int ret;
> @@ -795,6 +796,10 @@ static int pci_epf_test_core_init(struct pci_epf *epf)
> }
> }
>
> + linkup_notifier = epc_features->linkup_notifier;
> + if (!linkup_notifier)
> + queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work);
> +
> return 0;
> }
>
> @@ -890,8 +895,6 @@ static int pci_epf_test_bind(struct pci_epf *epf)
> const struct pci_epc_features *epc_features;
> enum pci_barno test_reg_bar = BAR_0;
> struct pci_epc *epc = epf->epc;
> - bool linkup_notifier = false;
> - bool core_init_notifier = false;
>
> if (WARN_ON_ONCE(!epc))
> return -EINVAL;
> @@ -902,8 +905,6 @@ static int pci_epf_test_bind(struct pci_epf *epf)
> return -EOPNOTSUPP;
> }
>
> - linkup_notifier = epc_features->linkup_notifier;
> - core_init_notifier = epc_features->core_init_notifier;
> test_reg_bar = pci_epc_get_first_free_bar(epc_features);
> if (test_reg_bar < 0)
> return -EINVAL;
> @@ -916,21 +917,12 @@ static int pci_epf_test_bind(struct pci_epf *epf)
> if (ret)
> return ret;
>
> - if (!core_init_notifier) {
> - ret = pci_epf_test_core_init(epf);
> - if (ret)
> - return ret;
> - }
> -
> epf_test->dma_supported = true;
>
> ret = pci_epf_test_init_dma_chan(epf_test);
> if (ret)
> epf_test->dma_supported = false;
>
> - if (!linkup_notifier && !core_init_notifier)
> - queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work);
> -
> return 0;
> }
>
> diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c
> index 0ea64e24ed61..3b21e28f9b59 100644
> --- a/drivers/pci/endpoint/pci-ep-cfs.c
> +++ b/drivers/pci/endpoint/pci-ep-cfs.c
> @@ -64,6 +64,9 @@ static int pci_secondary_epc_epf_link(struct config_item *epf_item,
> return ret;
> }
>
> + /* Send any pending EPC initialization complete to the EPF driver */
> + pci_epc_notify_pending_init(epc, epf);
> +
> return 0;
> }
>
> @@ -125,6 +128,9 @@ static int pci_primary_epc_epf_link(struct config_item *epf_item,
> return ret;
> }
>
> + /* Send any pending EPC initialization complete to the EPF driver */
> + pci_epc_notify_pending_init(epc, epf);
> +
> return 0;
> }
>
> @@ -230,6 +236,9 @@ static int pci_epc_epf_link(struct config_item *epc_item,
> return ret;
> }
>
> + /* Send any pending EPC initialization complete to the EPF driver */
> + pci_epc_notify_pending_init(epc, epf);
> +
> return 0;
> }
>
> diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
> index da3fc0795b0b..47d27ec7439d 100644
> --- a/drivers/pci/endpoint/pci-epc-core.c
> +++ b/drivers/pci/endpoint/pci-epc-core.c
> @@ -748,10 +748,32 @@ void pci_epc_init_notify(struct pci_epc *epc)
> epf->event_ops->core_init(epf);
> mutex_unlock(&epf->lock);
> }
> + epc->init_complete = true;
> mutex_unlock(&epc->list_lock);
> }
> EXPORT_SYMBOL_GPL(pci_epc_init_notify);
>
> +/**
> + * pci_epc_notify_pending_init() - Notify the pending EPC device initialization
> + * complete to the EPF device
> + * @epc: the EPC device whose core initialization is pending to be notified
> + * @epf: the EPF device to be notified
> + *
> + * Invoke to notify the pending EPC device initialization complete to the EPF
> + * device. This is used to deliver the notification if the EPC initialization
> + * got completed before the EPF driver bind.
> + */
> +void pci_epc_notify_pending_init(struct pci_epc *epc, struct pci_epf *epf)
> +{
> + if (epc->init_complete) {
> + mutex_lock(&epf->lock);
> + if (epf->event_ops && epf->event_ops->core_init)
> + epf->event_ops->core_init(epf);
> + mutex_unlock(&epf->lock);
> + }
> +}
> +EXPORT_SYMBOL_GPL(pci_epc_notify_pending_init);
> +
> /**
> * pci_epc_bme_notify() - Notify the EPF device that the EPC device has received
> * the BME event from the Root complex
> diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
> index cc2f70d061c8..acc5f96161fe 100644
> --- a/include/linux/pci-epc.h
> +++ b/include/linux/pci-epc.h
> @@ -128,6 +128,8 @@ struct pci_epc_mem {
> * @group: configfs group representing the PCI EPC device
> * @lock: mutex to protect pci_epc ops
> * @function_num_map: bitmap to manage physical function number
> + * @init_complete: flag to indicate whether the EPC initialization is complete
> + * or not
> */
> struct pci_epc {
> struct device dev;
> @@ -143,6 +145,7 @@ struct pci_epc {
> /* mutex to protect against concurrent access of EP controller */
> struct mutex lock;
> unsigned long function_num_map;
> + bool init_complete;
> };
>
> /**
> @@ -179,8 +182,6 @@ struct pci_epc_bar_desc {
> /**
> * struct pci_epc_features - features supported by a EPC device per function
> * @linkup_notifier: indicate if the EPC device can notify EPF driver on link up
> - * @core_init_notifier: indicate cores that can notify about their availability
> - * for initialization
> * @msi_capable: indicate if the endpoint function has MSI capability
> * @msix_capable: indicate if the endpoint function has MSI-X capability
> * @bar: array specifying the hardware description for each BAR
> @@ -188,7 +189,6 @@ struct pci_epc_bar_desc {
> */
> struct pci_epc_features {
> unsigned int linkup_notifier : 1;
> - unsigned int core_init_notifier : 1;
> unsigned int msi_capable : 1;
> unsigned int msix_capable : 1;
> struct pci_epc_bar_desc bar[PCI_STD_NUM_BARS];
> @@ -225,6 +225,7 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf,
> void pci_epc_linkup(struct pci_epc *epc);
> void pci_epc_linkdown(struct pci_epc *epc);
> void pci_epc_init_notify(struct pci_epc *epc);
> +void pci_epc_notify_pending_init(struct pci_epc *epc, struct pci_epf *epf);
> void pci_epc_bme_notify(struct pci_epc *epc);
> void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf,
> enum pci_epc_interface_type type);
>
> --
> 2.25.1
>