Merge branch 'pci/controller/dwc'

- Move DBI accesses from dw_pcie_ep_init() to dw_pcie_ep_init_complete() so
  drivers for endpoints that require Refclk for DBI access, e.g., qcom and
  tegra194, can control when this happens (Manivannan Sadhasivam)

- Add endpoint API kernel-doc (Manivannan Sadhasivam)

- Remove .deinit() callback and instead call rcar_gen4_pcie_ep_deinit()
  explicitly from rcar-gen4, which was the only user (Manivannan
  Sadhasivam)

- Rename dw_pcie_ep_exit() to dw_pcie_ep_deinit() to correspond with
  dw_pcie_ep_init() (Manivannan Sadhasivam)

- Add dw_pcie_ep_cleanup() for drivers that need to clean up eDMA resources
  when PERST# is asserted, e.g., qcom, tegra194 (Manivannan Sadhasivam)

- Rename dw_pcie_ep_init_complete() to dw_pcie_ep_init_registers() to
  better reflect the functionality (Manivannan Sadhasivam)

- Call dw_pcie_ep_init_registers() directly from drivers instead of from
  dw_pcie_ep_init() so drivers, e.g., qcom and tegra194, can do it when
  Refclk is available (Manivannan Sadhasivam)

- Remove the "core_init_notifier" flag, which previously identified drivers
  that required Refclk before DBI access, because it's now unnecessary
  (Manivannan Sadhasivam)

* pci/controller/dwc:
  PCI: endpoint: Remove "core_init_notifier" flag
  PCI: dwc: ep: Call dw_pcie_ep_init_registers() API directly from all glue drivers
  PCI: dwc: ep: Rename dw_pcie_ep_init_complete() to dw_pcie_ep_init_registers()
  PCI: dwc: ep: Introduce dw_pcie_ep_cleanup() API for drivers supporting PERST#
  PCI: dwc: ep: Rename dw_pcie_ep_exit() to dw_pcie_ep_deinit()
  PCI: dwc: ep: Remove deinit() callback from struct dw_pcie_ep_ops
  PCI: dwc: ep: Add Kernel-doc comments for APIs
  PCI: dwc: ep: Fix DBI access failure for drivers requiring refclk from host
This commit is contained in:
Bjorn Helgaas 2024-05-16 18:14:12 -05:00
commit 08f38906c9
20 changed files with 339 additions and 112 deletions

View File

@ -743,6 +743,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:

View File

@ -467,6 +467,15 @@ static int dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx,
return ret;
}
ret = dw_pcie_ep_init_registers(ep);
if (ret) {
dev_err(dev, "Failed to initialize DWC endpoint registers\n");
dw_pcie_ep_deinit(ep);
return ret;
}
dw_pcie_ep_init_notify(ep);
return 0;
}

View File

@ -1123,6 +1123,16 @@ static int imx6_add_pcie_ep(struct imx6_pcie *imx6_pcie,
dev_err(dev, "failed to initialize endpoint\n");
return ret;
}
ret = dw_pcie_ep_init_registers(ep);
if (ret) {
dev_err(dev, "Failed to initialize DWC endpoint registers\n");
dw_pcie_ep_deinit(ep);
return ret;
}
dw_pcie_ep_init_notify(ep);
/* Start LTSSM. */
imx6_pcie_ltssm_enable(dev);

View File

@ -1286,6 +1286,15 @@ static int ks_pcie_probe(struct platform_device *pdev)
ret = dw_pcie_ep_init(&pci->ep);
if (ret < 0)
goto err_get_sync;
ret = dw_pcie_ep_init_registers(&pci->ep);
if (ret) {
dev_err(dev, "Failed to initialize DWC endpoint registers\n");
goto err_ep_init;
}
dw_pcie_ep_init_notify(&pci->ep);
break;
default:
dev_err(dev, "INVALID device type %d\n", mode);
@ -1295,6 +1304,8 @@ static int ks_pcie_probe(struct platform_device *pdev)
return 0;
err_ep_init:
dw_pcie_ep_deinit(&pci->ep);
err_get_sync:
pm_runtime_put(dev);
pm_runtime_disable(dev);

View File

@ -279,6 +279,15 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
if (ret)
return ret;
ret = dw_pcie_ep_init_registers(&pci->ep);
if (ret) {
dev_err(dev, "Failed to initialize DWC endpoint registers\n");
dw_pcie_ep_deinit(&pci->ep);
return ret;
}
dw_pcie_ep_init_notify(&pci->ep);
return ls_pcie_ep_interrupt_init(pcie, pdev);
}

View File

@ -441,7 +441,20 @@ static int artpec6_pcie_probe(struct platform_device *pdev)
pci->ep.ops = &pcie_ep_ops;
return dw_pcie_ep_init(&pci->ep);
ret = dw_pcie_ep_init(&pci->ep);
if (ret)
return ret;
ret = dw_pcie_ep_init_registers(&pci->ep);
if (ret) {
dev_err(dev, "Failed to initialize DWC endpoint registers\n");
dw_pcie_ep_deinit(&pci->ep);
return ret;
}
dw_pcie_ep_init_notify(&pci->ep);
break;
default:
dev_err(dev, "INVALID device type %d\n", artpec6_pcie->mode);
}

View File

@ -15,6 +15,10 @@
#include <linux/pci-epc.h>
#include <linux/pci-epf.h>
/**
* dw_pcie_ep_linkup - Notify EPF drivers about Link Up event
* @ep: DWC EP device
*/
void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
{
struct pci_epc *epc = ep->epc;
@ -23,6 +27,10 @@ void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
}
EXPORT_SYMBOL_GPL(dw_pcie_ep_linkup);
/**
* dw_pcie_ep_init_notify - Notify EPF drivers about EPC initialization complete
* @ep: DWC EP device
*/
void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep)
{
struct pci_epc *epc = ep->epc;
@ -31,6 +39,14 @@ void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep)
}
EXPORT_SYMBOL_GPL(dw_pcie_ep_init_notify);
/**
* dw_pcie_ep_get_func_from_ep - Get the struct dw_pcie_ep_func corresponding to
* the endpoint function
* @ep: DWC EP device
* @func_no: Function number of the endpoint device
*
* Return: struct dw_pcie_ep_func if success, NULL otherwise.
*/
struct dw_pcie_ep_func *
dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no)
{
@ -61,6 +77,11 @@ static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, u8 func_no,
dw_pcie_dbi_ro_wr_dis(pci);
}
/**
* dw_pcie_ep_reset_bar - Reset endpoint BAR
* @pci: DWC PCI device
* @bar: BAR number of the endpoint
*/
void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
{
u8 func_no, funcs;
@ -440,6 +461,13 @@ static const struct pci_epc_ops epc_ops = {
.get_features = dw_pcie_ep_get_features,
};
/**
* dw_pcie_ep_raise_intx_irq - Raise INTx IRQ to the host
* @ep: DWC EP device
* @func_no: Function number of the endpoint
*
* Return: 0 if success, errono otherwise.
*/
int dw_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep, u8 func_no)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
@ -451,6 +479,14 @@ int dw_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep, u8 func_no)
}
EXPORT_SYMBOL_GPL(dw_pcie_ep_raise_intx_irq);
/**
* dw_pcie_ep_raise_msi_irq - Raise MSI IRQ to the host
* @ep: DWC EP device
* @func_no: Function number of the endpoint
* @interrupt_num: Interrupt number to be raised
*
* Return: 0 if success, errono otherwise.
*/
int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
u8 interrupt_num)
{
@ -500,6 +536,15 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
}
EXPORT_SYMBOL_GPL(dw_pcie_ep_raise_msi_irq);
/**
* dw_pcie_ep_raise_msix_irq_doorbell - Raise MSI-X to the host using Doorbell
* method
* @ep: DWC EP device
* @func_no: Function number of the endpoint device
* @interrupt_num: Interrupt number to be raised
*
* Return: 0 if success, errno otherwise.
*/
int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no,
u16 interrupt_num)
{
@ -519,6 +564,14 @@ int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no,
return 0;
}
/**
* dw_pcie_ep_raise_msix_irq - Raise MSI-X to the host
* @ep: DWC EP device
* @func_no: Function number of the endpoint device
* @interrupt_num: Interrupt number to be raised
*
* Return: 0 if success, errno otherwise.
*/
int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
u16 interrupt_num)
{
@ -566,22 +619,42 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
return 0;
}
void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
/**
* dw_pcie_ep_cleanup - Cleanup DWC EP resources after fundamental reset
* @ep: DWC EP device
*
* Cleans up the DWC EP specific resources like eDMA etc... after fundamental
* reset like PERST#. Note that this API is only applicable for drivers
* supporting PERST# or any other methods of fundamental reset.
*/
void dw_pcie_ep_cleanup(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct pci_epc *epc = ep->epc;
dw_pcie_edma_remove(pci);
ep->epc->init_complete = false;
}
EXPORT_SYMBOL_GPL(dw_pcie_ep_cleanup);
/**
* dw_pcie_ep_deinit - Deinitialize the endpoint device
* @ep: DWC EP device
*
* Deinitialize the endpoint device. EPC device is not destroyed since that will
* be taken care by Devres.
*/
void dw_pcie_ep_deinit(struct dw_pcie_ep *ep)
{
struct pci_epc *epc = ep->epc;
dw_pcie_ep_cleanup(ep);
pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
epc->mem->window.page_size);
pci_epc_mem_exit(epc);
if (ep->ops->deinit)
ep->ops->deinit(ep);
}
EXPORT_SYMBOL_GPL(dw_pcie_ep_exit);
EXPORT_SYMBOL_GPL(dw_pcie_ep_deinit);
static unsigned int dw_pcie_ep_find_ext_capability(struct dw_pcie *pci, int cap)
{
@ -601,14 +674,27 @@ static unsigned int dw_pcie_ep_find_ext_capability(struct dw_pcie *pci, int cap)
return 0;
}
int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
/**
* dw_pcie_ep_init_registers - Initialize DWC EP specific registers
* @ep: DWC EP device
*
* Initialize the registers (CSRs) specific to DWC EP. This API should be called
* only when the endpoint receives an active refclk (either from host or
* generated locally).
*/
int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct dw_pcie_ep_func *ep_func;
struct device *dev = pci->dev;
struct pci_epc *epc = ep->epc;
unsigned int offset, ptm_cap_base;
unsigned int nbars;
u8 hdr_type;
u8 func_no;
int i, ret;
void *addr;
u32 reg;
int i;
hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE) &
PCI_HEADER_TYPE_MASK;
@ -619,6 +705,58 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
return -EIO;
}
dw_pcie_version_detect(pci);
dw_pcie_iatu_detect(pci);
ret = dw_pcie_edma_detect(pci);
if (ret)
return ret;
if (!ep->ib_window_map) {
ep->ib_window_map = devm_bitmap_zalloc(dev, pci->num_ib_windows,
GFP_KERNEL);
if (!ep->ib_window_map)
goto err_remove_edma;
}
if (!ep->ob_window_map) {
ep->ob_window_map = devm_bitmap_zalloc(dev, pci->num_ob_windows,
GFP_KERNEL);
if (!ep->ob_window_map)
goto err_remove_edma;
}
if (!ep->outbound_addr) {
addr = devm_kcalloc(dev, pci->num_ob_windows, sizeof(phys_addr_t),
GFP_KERNEL);
if (!addr)
goto err_remove_edma;
ep->outbound_addr = addr;
}
for (func_no = 0; func_no < epc->max_functions; func_no++) {
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
if (ep_func)
continue;
ep_func = devm_kzalloc(dev, sizeof(*ep_func), GFP_KERNEL);
if (!ep_func)
goto err_remove_edma;
ep_func->func_no = func_no;
ep_func->msi_cap = dw_pcie_ep_find_capability(ep, func_no,
PCI_CAP_ID_MSI);
ep_func->msix_cap = dw_pcie_ep_find_capability(ep, func_no,
PCI_CAP_ID_MSIX);
list_add_tail(&ep_func->list, &ep->func_list);
}
if (ep->ops->init)
ep->ops->init(ep);
offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR);
ptm_cap_base = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_PTM);
@ -658,22 +796,32 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
dw_pcie_dbi_ro_wr_dis(pci);
return 0;
}
EXPORT_SYMBOL_GPL(dw_pcie_ep_init_complete);
err_remove_edma:
dw_pcie_edma_remove(pci);
return ret;
}
EXPORT_SYMBOL_GPL(dw_pcie_ep_init_registers);
/**
* dw_pcie_ep_init - Initialize the endpoint device
* @ep: DWC EP device
*
* Initialize the endpoint device. Allocate resources and create the EPC
* device with the endpoint framework.
*
* Return: 0 if success, errno otherwise.
*/
int dw_pcie_ep_init(struct dw_pcie_ep *ep)
{
int ret;
void *addr;
u8 func_no;
struct resource *res;
struct pci_epc *epc;
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct device *dev = pci->dev;
struct platform_device *pdev = to_platform_device(dev);
struct device_node *np = dev->of_node;
const struct pci_epc_features *epc_features;
struct dw_pcie_ep_func *ep_func;
INIT_LIST_HEAD(&ep->func_list);
@ -691,26 +839,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
if (ep->ops->pre_init)
ep->ops->pre_init(ep);
dw_pcie_version_detect(pci);
dw_pcie_iatu_detect(pci);
ep->ib_window_map = devm_bitmap_zalloc(dev, pci->num_ib_windows,
GFP_KERNEL);
if (!ep->ib_window_map)
return -ENOMEM;
ep->ob_window_map = devm_bitmap_zalloc(dev, pci->num_ob_windows,
GFP_KERNEL);
if (!ep->ob_window_map)
return -ENOMEM;
addr = devm_kcalloc(dev, pci->num_ob_windows, sizeof(phys_addr_t),
GFP_KERNEL);
if (!addr)
return -ENOMEM;
ep->outbound_addr = addr;
epc = devm_pci_epc_create(dev, &epc_ops);
if (IS_ERR(epc)) {
dev_err(dev, "Failed to create epc device\n");
@ -724,28 +852,11 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
if (ret < 0)
epc->max_functions = 1;
for (func_no = 0; func_no < epc->max_functions; func_no++) {
ep_func = devm_kzalloc(dev, sizeof(*ep_func), GFP_KERNEL);
if (!ep_func)
return -ENOMEM;
ep_func->func_no = func_no;
ep_func->msi_cap = dw_pcie_ep_find_capability(ep, func_no,
PCI_CAP_ID_MSI);
ep_func->msix_cap = dw_pcie_ep_find_capability(ep, func_no,
PCI_CAP_ID_MSIX);
list_add_tail(&ep_func->list, &ep->func_list);
}
if (ep->ops->init)
ep->ops->init(ep);
ret = pci_epc_mem_init(epc, ep->phys_base, ep->addr_size,
ep->page_size);
if (ret < 0) {
dev_err(dev, "Failed to initialize address space\n");
goto err_ep_deinit;
return ret;
}
ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys,
@ -756,36 +867,11 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
goto err_exit_epc_mem;
}
ret = dw_pcie_edma_detect(pci);
if (ret)
goto err_free_epc_mem;
if (ep->ops->get_features) {
epc_features = ep->ops->get_features(ep);
if (epc_features->core_init_notifier)
return 0;
}
ret = dw_pcie_ep_init_complete(ep);
if (ret)
goto err_remove_edma;
return 0;
err_remove_edma:
dw_pcie_edma_remove(pci);
err_free_epc_mem:
pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
epc->mem->window.page_size);
err_exit_epc_mem:
pci_epc_mem_exit(epc);
err_ep_deinit:
if (ep->ops->deinit)
ep->ops->deinit(ep);
return ret;
}
EXPORT_SYMBOL_GPL(dw_pcie_ep_init);

View File

@ -145,6 +145,17 @@ static int dw_plat_pcie_probe(struct platform_device *pdev)
pci->ep.ops = &pcie_ep_ops;
ret = dw_pcie_ep_init(&pci->ep);
if (ret)
return ret;
ret = dw_pcie_ep_init_registers(&pci->ep);
if (ret) {
dev_err(dev, "Failed to initialize DWC endpoint registers\n");
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);

View File

@ -333,7 +333,6 @@ struct dw_pcie_rp {
struct dw_pcie_ep_ops {
void (*pre_init)(struct dw_pcie_ep *ep);
void (*init)(struct dw_pcie_ep *ep);
void (*deinit)(struct dw_pcie_ep *ep);
int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no,
unsigned int type, u16 interrupt_num);
const struct pci_epc_features* (*get_features)(struct dw_pcie_ep *ep);
@ -670,9 +669,10 @@ static inline void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus,
#ifdef CONFIG_PCIE_DW_EP
void dw_pcie_ep_linkup(struct dw_pcie_ep *ep);
int dw_pcie_ep_init(struct dw_pcie_ep *ep);
int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep);
int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep);
void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep);
void dw_pcie_ep_exit(struct dw_pcie_ep *ep);
void dw_pcie_ep_deinit(struct dw_pcie_ep *ep);
void dw_pcie_ep_cleanup(struct dw_pcie_ep *ep);
int dw_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep, u8 func_no);
int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
u8 interrupt_num);
@ -693,7 +693,7 @@ static inline int dw_pcie_ep_init(struct dw_pcie_ep *ep)
return 0;
}
static inline int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
static inline int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep)
{
return 0;
}
@ -702,7 +702,11 @@ static inline void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep)
{
}
static inline void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
static inline void dw_pcie_ep_deinit(struct dw_pcie_ep *ep)
{
}
static inline void dw_pcie_ep_cleanup(struct dw_pcie_ep *ep)
{
}

View File

@ -396,6 +396,7 @@ static int keembay_pcie_probe(struct platform_device *pdev)
struct keembay_pcie *pcie;
struct dw_pcie *pci;
enum dw_pcie_device_mode mode;
int ret;
data = device_get_match_data(dev);
if (!data)
@ -430,11 +431,26 @@ static int keembay_pcie_probe(struct platform_device *pdev)
return -ENODEV;
pci->ep.ops = &keembay_pcie_ep_ops;
return dw_pcie_ep_init(&pci->ep);
ret = dw_pcie_ep_init(&pci->ep);
if (ret)
return ret;
ret = dw_pcie_ep_init_registers(&pci->ep);
if (ret) {
dev_err(dev, "Failed to initialize DWC endpoint registers\n");
dw_pcie_ep_deinit(&pci->ep);
return ret;
}
dw_pcie_ep_init_notify(&pci->ep);
break;
default:
dev_err(dev, "Invalid device type %d\n", pcie->mode);
return -ENODEV;
}
return 0;
}
static const struct keembay_pcie_of_data keembay_pcie_rc_of_data = {

View File

@ -463,7 +463,7 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci)
PARF_INT_ALL_LINK_UP | PARF_INT_ALL_EDMA;
writel_relaxed(val, pcie_ep->parf + PARF_INT_ALL_MASK);
ret = dw_pcie_ep_init_complete(&pcie_ep->pci.ep);
ret = dw_pcie_ep_init_registers(&pcie_ep->pci.ep);
if (ret) {
dev_err(dev, "Failed to complete initialization: %d\n", ret);
goto err_disable_resources;
@ -507,6 +507,7 @@ static void qcom_pcie_perst_assert(struct dw_pcie *pci)
return;
}
dw_pcie_ep_cleanup(&pci->ep);
qcom_pcie_disable_resources(pcie_ep);
pcie_ep->link_status = QCOM_PCIE_EP_LINK_DISABLED;
}
@ -774,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,

View File

@ -352,11 +352,8 @@ static void rcar_gen4_pcie_ep_init(struct dw_pcie_ep *ep)
dw_pcie_ep_reset_bar(pci, bar);
}
static void rcar_gen4_pcie_ep_deinit(struct dw_pcie_ep *ep)
static void rcar_gen4_pcie_ep_deinit(struct rcar_gen4_pcie *rcar)
{
struct dw_pcie *dw = to_dw_pcie_from_ep(ep);
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
writel(0, rcar->base + PCIEDMAINTSTSEN);
rcar_gen4_pcie_common_deinit(rcar);
}
@ -410,7 +407,6 @@ static unsigned int rcar_gen4_pcie_ep_get_dbi2_offset(struct dw_pcie_ep *ep,
static const struct dw_pcie_ep_ops pcie_ep_ops = {
.pre_init = rcar_gen4_pcie_ep_pre_init,
.init = rcar_gen4_pcie_ep_init,
.deinit = rcar_gen4_pcie_ep_deinit,
.raise_irq = rcar_gen4_pcie_ep_raise_irq,
.get_features = rcar_gen4_pcie_ep_get_features,
.get_dbi_offset = rcar_gen4_pcie_ep_get_dbi_offset,
@ -420,18 +416,36 @@ static const struct dw_pcie_ep_ops pcie_ep_ops = {
static int rcar_gen4_add_dw_pcie_ep(struct rcar_gen4_pcie *rcar)
{
struct dw_pcie_ep *ep = &rcar->dw.ep;
struct device *dev = rcar->dw.dev;
int ret;
if (!IS_ENABLED(CONFIG_PCIE_RCAR_GEN4_EP))
return -ENODEV;
ep->ops = &pcie_ep_ops;
return dw_pcie_ep_init(ep);
ret = dw_pcie_ep_init(ep);
if (ret) {
rcar_gen4_pcie_ep_deinit(rcar);
return ret;
}
ret = dw_pcie_ep_init_registers(ep);
if (ret) {
dev_err(dev, "Failed to initialize DWC endpoint registers\n");
dw_pcie_ep_deinit(ep);
rcar_gen4_pcie_ep_deinit(rcar);
}
dw_pcie_ep_init_notify(ep);
return ret;
}
static void rcar_gen4_remove_dw_pcie_ep(struct rcar_gen4_pcie *rcar)
{
dw_pcie_ep_exit(&rcar->dw.ep);
dw_pcie_ep_deinit(&rcar->dw.ep);
rcar_gen4_pcie_ep_deinit(rcar);
}
/* Common */

View File

@ -1715,6 +1715,8 @@ 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);
dw_pcie_ep_cleanup(&pcie->pci.ep);
reset_control_assert(pcie->core_rst);
tegra_pcie_disable_phy(pcie);
@ -1895,7 +1897,7 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
val = (upper_32_bits(ep->msi_mem_phys) & MSIX_ADDR_MATCH_HIGH_OFF_MASK);
dw_pcie_writel_dbi(pci, MSIX_ADDR_MATCH_HIGH_OFF, val);
ret = dw_pcie_ep_init_complete(ep);
ret = dw_pcie_ep_init_registers(ep);
if (ret) {
dev_err(dev, "Failed to complete initialization: %d\n", ret);
goto fail_init_complete;
@ -2004,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,

View File

@ -399,7 +399,20 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev)
return ret;
priv->pci.ep.ops = &uniphier_pcie_ep_ops;
return dw_pcie_ep_init(&priv->pci.ep);
ret = dw_pcie_ep_init(&priv->pci.ep);
if (ret)
return ret;
ret = dw_pcie_ep_init_registers(&priv->pci.ep);
if (ret) {
dev_err(dev, "Failed to initialize DWC endpoint registers\n");
dw_pcie_ep_deinit(&priv->pci.ep);
return ret;
}
dw_pcie_ep_init_notify(&priv->pci.ep);
return 0;
}
static const struct uniphier_pcie_ep_soc_data uniphier_pro5_data = {

View File

@ -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:

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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);