Skip to content

Commit 869bc52

Browse files
Mani-Sadhasivamkwilczynski
authored andcommitted
PCI: dwc: ep: Fix DBI access failure for drivers requiring refclk from host
The DWC glue drivers requiring an active reference clock from the PCIe host for initializing their PCIe EP core, set a flag called 'core_init_notifier' to let DWC driver know that these drivers need a special attention during initialization. In these drivers, access to the hw registers (like DBI) before receiving the active refclk from host will result in access failure and also could cause a whole system hang. But the current DWC EP driver doesn't honor the requirements of the drivers setting 'core_init_notifier' flag and tries to access the DBI registers during dw_pcie_ep_init(). This causes the system hang for glue drivers such as Tegra194 and Qcom EP as they depend on refclk from host and have set the above mentioned flag. To workaround this issue, users of the affected platforms have to maintain the dependency with the PCIe host by booting the PCIe EP after host boot. But this won't provide a good user experience, since PCIe EP is _one_ of the features of those platforms and it doesn't make sense to delay the whole platform booting due to PCIe requiring active refclk. So to fix this issue, let's move all the DBI access from dw_pcie_ep_init() in the DWC EP driver to the dw_pcie_ep_init_complete() API. This API will only be called by the drivers setting 'core_init_notifier' flag once refclk is received from host. For the rest of the drivers that gets the refclk locally, this API will be called within dw_pcie_ep_init(). Link: https://lore.kernel.org/linux-pci/[email protected] Fixes: e966f73 ("PCI: dwc: Refactor core initialization code for EP mode") Co-developed-by: Vidya Sagar <[email protected]> Signed-off-by: Vidya Sagar <[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]>
1 parent 4cece76 commit 869bc52

File tree

1 file changed

+71
-49
lines changed

1 file changed

+71
-49
lines changed

drivers/pci/controller/dwc/pcie-designware-ep.c

Lines changed: 71 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -604,11 +604,16 @@ static unsigned int dw_pcie_ep_find_ext_capability(struct dw_pcie *pci, int cap)
604604
int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
605605
{
606606
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
607+
struct dw_pcie_ep_func *ep_func;
608+
struct device *dev = pci->dev;
609+
struct pci_epc *epc = ep->epc;
607610
unsigned int offset, ptm_cap_base;
608611
unsigned int nbars;
609612
u8 hdr_type;
613+
u8 func_no;
614+
int i, ret;
615+
void *addr;
610616
u32 reg;
611-
int i;
612617

613618
hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE) &
614619
PCI_HEADER_TYPE_MASK;
@@ -619,6 +624,58 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
619624
return -EIO;
620625
}
621626

627+
dw_pcie_version_detect(pci);
628+
629+
dw_pcie_iatu_detect(pci);
630+
631+
ret = dw_pcie_edma_detect(pci);
632+
if (ret)
633+
return ret;
634+
635+
if (!ep->ib_window_map) {
636+
ep->ib_window_map = devm_bitmap_zalloc(dev, pci->num_ib_windows,
637+
GFP_KERNEL);
638+
if (!ep->ib_window_map)
639+
goto err_remove_edma;
640+
}
641+
642+
if (!ep->ob_window_map) {
643+
ep->ob_window_map = devm_bitmap_zalloc(dev, pci->num_ob_windows,
644+
GFP_KERNEL);
645+
if (!ep->ob_window_map)
646+
goto err_remove_edma;
647+
}
648+
649+
if (!ep->outbound_addr) {
650+
addr = devm_kcalloc(dev, pci->num_ob_windows, sizeof(phys_addr_t),
651+
GFP_KERNEL);
652+
if (!addr)
653+
goto err_remove_edma;
654+
ep->outbound_addr = addr;
655+
}
656+
657+
for (func_no = 0; func_no < epc->max_functions; func_no++) {
658+
659+
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
660+
if (ep_func)
661+
continue;
662+
663+
ep_func = devm_kzalloc(dev, sizeof(*ep_func), GFP_KERNEL);
664+
if (!ep_func)
665+
goto err_remove_edma;
666+
667+
ep_func->func_no = func_no;
668+
ep_func->msi_cap = dw_pcie_ep_find_capability(ep, func_no,
669+
PCI_CAP_ID_MSI);
670+
ep_func->msix_cap = dw_pcie_ep_find_capability(ep, func_no,
671+
PCI_CAP_ID_MSIX);
672+
673+
list_add_tail(&ep_func->list, &ep->func_list);
674+
}
675+
676+
if (ep->ops->init)
677+
ep->ops->init(ep);
678+
622679
offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR);
623680
ptm_cap_base = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_PTM);
624681

@@ -658,22 +715,24 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
658715
dw_pcie_dbi_ro_wr_dis(pci);
659716

660717
return 0;
718+
719+
err_remove_edma:
720+
dw_pcie_edma_remove(pci);
721+
722+
return ret;
661723
}
662724
EXPORT_SYMBOL_GPL(dw_pcie_ep_init_complete);
663725

664726
int dw_pcie_ep_init(struct dw_pcie_ep *ep)
665727
{
666728
int ret;
667-
void *addr;
668-
u8 func_no;
669729
struct resource *res;
670730
struct pci_epc *epc;
671731
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
672732
struct device *dev = pci->dev;
673733
struct platform_device *pdev = to_platform_device(dev);
674734
struct device_node *np = dev->of_node;
675735
const struct pci_epc_features *epc_features;
676-
struct dw_pcie_ep_func *ep_func;
677736

678737
INIT_LIST_HEAD(&ep->func_list);
679738

@@ -691,26 +750,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
691750
if (ep->ops->pre_init)
692751
ep->ops->pre_init(ep);
693752

694-
dw_pcie_version_detect(pci);
695-
696-
dw_pcie_iatu_detect(pci);
697-
698-
ep->ib_window_map = devm_bitmap_zalloc(dev, pci->num_ib_windows,
699-
GFP_KERNEL);
700-
if (!ep->ib_window_map)
701-
return -ENOMEM;
702-
703-
ep->ob_window_map = devm_bitmap_zalloc(dev, pci->num_ob_windows,
704-
GFP_KERNEL);
705-
if (!ep->ob_window_map)
706-
return -ENOMEM;
707-
708-
addr = devm_kcalloc(dev, pci->num_ob_windows, sizeof(phys_addr_t),
709-
GFP_KERNEL);
710-
if (!addr)
711-
return -ENOMEM;
712-
ep->outbound_addr = addr;
713-
714753
epc = devm_pci_epc_create(dev, &epc_ops);
715754
if (IS_ERR(epc)) {
716755
dev_err(dev, "Failed to create epc device\n");
@@ -724,23 +763,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
724763
if (ret < 0)
725764
epc->max_functions = 1;
726765

727-
for (func_no = 0; func_no < epc->max_functions; func_no++) {
728-
ep_func = devm_kzalloc(dev, sizeof(*ep_func), GFP_KERNEL);
729-
if (!ep_func)
730-
return -ENOMEM;
731-
732-
ep_func->func_no = func_no;
733-
ep_func->msi_cap = dw_pcie_ep_find_capability(ep, func_no,
734-
PCI_CAP_ID_MSI);
735-
ep_func->msix_cap = dw_pcie_ep_find_capability(ep, func_no,
736-
PCI_CAP_ID_MSIX);
737-
738-
list_add_tail(&ep_func->list, &ep->func_list);
739-
}
740-
741-
if (ep->ops->init)
742-
ep->ops->init(ep);
743-
744766
ret = pci_epc_mem_init(epc, ep->phys_base, ep->addr_size,
745767
ep->page_size);
746768
if (ret < 0) {
@@ -756,25 +778,25 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
756778
goto err_exit_epc_mem;
757779
}
758780

759-
ret = dw_pcie_edma_detect(pci);
760-
if (ret)
761-
goto err_free_epc_mem;
762-
763781
if (ep->ops->get_features) {
764782
epc_features = ep->ops->get_features(ep);
765783
if (epc_features->core_init_notifier)
766784
return 0;
767785
}
768786

787+
/*
788+
* NOTE:- Avoid accessing the hardware (Ex:- DBI space) before this
789+
* step as platforms that implement 'core_init_notifier' feature may
790+
* not have the hardware ready (i.e. core initialized) for access
791+
* (Ex: tegra194). Any hardware access on such platforms result
792+
* in system hang.
793+
*/
769794
ret = dw_pcie_ep_init_complete(ep);
770795
if (ret)
771-
goto err_remove_edma;
796+
goto err_free_epc_mem;
772797

773798
return 0;
774799

775-
err_remove_edma:
776-
dw_pcie_edma_remove(pci);
777-
778800
err_free_epc_mem:
779801
pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
780802
epc->mem->window.page_size);

0 commit comments

Comments
 (0)