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 >