Skip to content

Commit

Permalink
PCI: endpoint: Remove "core_init_notifier" flag
Browse files Browse the repository at this point in the history
"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.

Link: https://lore.kernel.org/linux-pci/[email protected]
Tested-by: Niklas Cassel <[email protected]>
Signed-off-by: Manivannan Sadhasivam <[email protected]>
Signed-off-by: Krzysztof Wilczyński <[email protected]>
Reviewed-by: Frank Li <[email protected]>
Reviewed-by: Niklas Cassel <[email protected]>
  • Loading branch information
Mani-Sadhasivam authored and kwilczynski committed Apr 10, 2024
1 parent df69e17 commit a01e721
Show file tree
Hide file tree
Showing 19 changed files with 65 additions and 18 deletions.
2 changes: 2 additions & 0 deletions drivers/pci/controller/cadence/pcie-cadence-ep.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 2 additions & 0 deletions drivers/pci/controller/dwc/pci-dra7xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,8 @@ static int dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx,
return ret;
}

dw_pcie_ep_init_notify(ep);

return 0;
}

Expand Down
2 changes: 2 additions & 0 deletions drivers/pci/controller/dwc/pci-imx6.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 2 additions & 0 deletions drivers/pci/controller/dwc/pci-keystone.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions drivers/pci/controller/dwc/pci-layerscape-ep.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
2 changes: 2 additions & 0 deletions drivers/pci/controller/dwc/pcie-artpec6.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions drivers/pci/controller/dwc/pcie-designware-ep.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 2 additions & 0 deletions drivers/pci/controller/dwc/pcie-designware-plat.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions drivers/pci/controller/dwc/pcie-keembay.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 0 additions & 1 deletion drivers/pci/controller/dwc/pcie-qcom-ep.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions drivers/pci/controller/dwc/pcie-rcar-gen4.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
1 change: 0 additions & 1 deletion drivers/pci/controller/dwc/pcie-tegra194.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions drivers/pci/controller/dwc/pcie-uniphier-ep.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
2 changes: 2 additions & 0 deletions drivers/pci/controller/pcie-rcar-ep.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 2 additions & 0 deletions drivers/pci/controller/pcie-rockchip-ep.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
18 changes: 5 additions & 13 deletions drivers/pci/endpoint/functions/pci-epf-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
}

Expand Down
9 changes: 9 additions & 0 deletions drivers/pci/endpoint/pci-ep-cfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down
22 changes: 22 additions & 0 deletions drivers/pci/endpoint/pci-epc-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 4 additions & 3 deletions include/linux/pci-epc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
};

/**
Expand Down Expand Up @@ -179,16 +182,13 @@ 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
* @align: alignment size required for BAR buffer allocation
*/
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];
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit a01e721

Please sign in to comment.