Re: [PATCH 1/4] PCI: dwc: Add new feature to skip core initialization
From: Kishon Vijay Abraham I
Date: Wed Nov 27 2019 - 03:15:56 EST
Hi,
On 13/11/19 2:38 PM, Vidya Sagar wrote:
> Add a new feature 'skip_core_init' that can be set by platform drivers
> of devices that do not have their core registers available until reference
> clock from host is available (Ex:- Tegra194) to indicate DesignWare
> endpoint mode sub-system to not perform core registers initialization.
> Existing dw_pcie_ep_init() is refactored and all the code that touches
> registers is extracted to form a new API dw_pcie_ep_init_complete() that
> can be called later by platform drivers setting 'skip_core_init' to '1'.
>
> Signed-off-by: Vidya Sagar <vidyas@xxxxxxxxxx>
> ---
> .../pci/controller/dwc/pcie-designware-ep.c | 72 +++++++++++--------
> drivers/pci/controller/dwc/pcie-designware.h | 6 ++
> include/linux/pci-epc.h | 1 +
> 3 files changed, 51 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> index 3dd2e2697294..06f4379be8a3 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> @@ -492,19 +492,53 @@ static unsigned int dw_pcie_ep_find_ext_capability(struct dw_pcie *pci, int cap)
> return 0;
> }
>
> -int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> +int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
> {
> + struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> + unsigned int offset;
> + unsigned int nbars;
> + u8 hdr_type;
> + u32 reg;
> int i;
> +
> + hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE);
> + if (hdr_type != PCI_HEADER_TYPE_NORMAL) {
> + dev_err(pci->dev,
> + "PCIe controller is not set to EP mode (hdr_type:0x%x)!\n",
> + hdr_type);
> + return -EIO;
> + }
> +
> + ep->msi_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI);
> +
> + ep->msix_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSIX);
> +
> + offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR);
> + if (offset) {
> + reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL);
> + nbars = (reg & PCI_REBAR_CTRL_NBAR_MASK) >>
> + PCI_REBAR_CTRL_NBAR_SHIFT;
> +
> + dw_pcie_dbi_ro_wr_en(pci);
> + for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL)
> + dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, 0x0);
> + dw_pcie_dbi_ro_wr_dis(pci);
> + }
> +
> + dw_pcie_setup(pci);
> +
> + return 0;
> +}
> +
> +int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> +{
> int ret;
> - u32 reg;
> void *addr;
> - u8 hdr_type;
> - unsigned int nbars;
> - unsigned int offset;
> struct pci_epc *epc;
> struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> struct device *dev = pci->dev;
> struct device_node *np = dev->of_node;
> + const struct pci_epc_features *epc_features;
>
> if (!pci->dbi_base || !pci->dbi_base2) {
> dev_err(dev, "dbi_base/dbi_base2 is not populated\n");
> @@ -563,13 +597,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> if (ep->ops->ep_init)
> ep->ops->ep_init(ep);
>
> - hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE);
> - if (hdr_type != PCI_HEADER_TYPE_NORMAL) {
> - dev_err(pci->dev, "PCIe controller is not set to EP mode (hdr_type:0x%x)!\n",
> - hdr_type);
> - return -EIO;
> - }
> -
> ret = of_property_read_u8(np, "max-functions", &epc->max_functions);
> if (ret < 0)
> epc->max_functions = 1;
> @@ -587,23 +614,12 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> dev_err(dev, "Failed to reserve memory for MSI/MSI-X\n");
> return -ENOMEM;
> }
> - ep->msi_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI);
>
> - ep->msix_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSIX);
> -
> - offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR);
> - if (offset) {
> - reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL);
> - nbars = (reg & PCI_REBAR_CTRL_NBAR_MASK) >>
> - PCI_REBAR_CTRL_NBAR_SHIFT;
> -
> - dw_pcie_dbi_ro_wr_en(pci);
> - for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL)
> - dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, 0x0);
> - dw_pcie_dbi_ro_wr_dis(pci);
> + if (ep->ops->get_features) {
> + epc_features = ep->ops->get_features(ep);
> + if (epc_features->skip_core_init)
> + return 0;
> }
>
> - dw_pcie_setup(pci);
> -
> - return 0;
> + return dw_pcie_ep_init_complete(ep);
> }
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index 5accdd6bc388..340783e9032e 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -399,6 +399,7 @@ static inline int dw_pcie_allocate_domains(struct pcie_port *pp)
> #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);
> void dw_pcie_ep_exit(struct dw_pcie_ep *ep);
> int dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no);
> int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
> @@ -416,6 +417,11 @@ 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)
> +{
> + return 0;
> +}
> +
> static inline void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
> {
> }
> diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
> index 36644ccd32ac..241e6a6f39fb 100644
> --- a/include/linux/pci-epc.h
> +++ b/include/linux/pci-epc.h
> @@ -121,6 +121,7 @@ struct pci_epc_features {
> u8 bar_fixed_64bit;
> u64 bar_fixed_size[PCI_STD_NUM_BARS];
> size_t align;
> + bool skip_core_init;
This looks more like a designware specific change. Why is it added to the core
pci_epc_features?
Thanks
Kishon