mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 14:12:06 +00:00
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:
commit
08f38906c9
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -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 = {
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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 = {
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user