From 9f9e59a4809563f24e3d1377aa804a4b7386a418 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 26 Oct 2020 13:16:52 -0500 Subject: PCI: dwc: Support multiple ATU memory regions The current ATU setup only supports a single memory resource which isn't sufficient if there are also prefetchable memory regions. In order to support multiple memory regions, we need to move away from fixed ATU slots and rework the assignment. As there's always an ATU entry for config space, let's assign index 0 to config space. Then we assign memory resources to index 1 and up. Finally, if we have an I/O region and slots remaining, we assign the I/O region last. If there aren't remaining slots, we keep the same config and I/O space sharing. Link: https://lore.kernel.org/r/20201026181652.418729-1-robh@kernel.org Tested-by: Vidya Sagar Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Reviewed-by: Vidya Sagar Acked-by: Jingoo Han Cc: Vidya Sagar Cc: Jingoo Han Cc: Gustavo Pimentel Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-designware-host.c | 54 ++++++++++++++--------- drivers/pci/controller/dwc/pcie-designware.h | 6 +-- 2 files changed, 34 insertions(+), 26 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 44c2a6572199..a6ffab9b537e 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -464,9 +464,7 @@ static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus, type = PCIE_ATU_TYPE_CFG1; - dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1, - type, pp->cfg0_base, - busdev, pp->cfg0_size); + dw_pcie_prog_outbound_atu(pci, 0, type, pp->cfg0_base, busdev, pp->cfg0_size); return pp->va_cfg0_base + where; } @@ -480,9 +478,8 @@ static int dw_pcie_rd_other_conf(struct pci_bus *bus, unsigned int devfn, ret = pci_generic_config_read(bus, devfn, where, size, val); - if (!ret && pci->num_viewport <= 2) - dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1, - PCIE_ATU_TYPE_IO, pp->io_base, + if (!ret && pci->io_cfg_atu_shared) + dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base, pp->io_bus_addr, pp->io_size); return ret; @@ -497,9 +494,8 @@ static int dw_pcie_wr_other_conf(struct pci_bus *bus, unsigned int devfn, ret = pci_generic_config_write(bus, devfn, where, size, val); - if (!ret && pci->num_viewport <= 2) - dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1, - PCIE_ATU_TYPE_IO, pp->io_base, + if (!ret && pci->io_cfg_atu_shared) + dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base, pp->io_bus_addr, pp->io_size); return ret; @@ -586,21 +582,35 @@ void dw_pcie_setup_rc(struct pcie_port *pp) * ATU, so we should not program the ATU here. */ if (pp->bridge->child_ops == &dw_child_pcie_ops) { - struct resource_entry *tmp, *entry = NULL; + int atu_idx = 0; + struct resource_entry *entry; /* Get last memory resource entry */ - resource_list_for_each_entry(tmp, &pp->bridge->windows) - if (resource_type(tmp->res) == IORESOURCE_MEM) - entry = tmp; - - dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0, - PCIE_ATU_TYPE_MEM, entry->res->start, - entry->res->start - entry->offset, - resource_size(entry->res)); - if (pci->num_viewport > 2) - dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2, - PCIE_ATU_TYPE_IO, pp->io_base, - pp->io_bus_addr, pp->io_size); + resource_list_for_each_entry(entry, &pp->bridge->windows) { + if (resource_type(entry->res) != IORESOURCE_MEM) + continue; + + if (pci->num_viewport <= ++atu_idx) + break; + + dw_pcie_prog_outbound_atu(pci, atu_idx, + PCIE_ATU_TYPE_MEM, entry->res->start, + entry->res->start - entry->offset, + resource_size(entry->res)); + } + + if (pp->io_size) { + if (pci->num_viewport > ++atu_idx) + dw_pcie_prog_outbound_atu(pci, atu_idx, + PCIE_ATU_TYPE_IO, pp->io_base, + pp->io_bus_addr, pp->io_size); + else + pci->io_cfg_atu_shared = true; + } + + if (pci->num_viewport <= atu_idx) + dev_warn(pci->dev, "Resources exceed number of ATU entries (%d)", + pci->num_viewport); } dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 9d2f511f13fa..ed19c34dd0fe 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -80,9 +80,6 @@ #define PCIE_ATU_VIEWPORT 0x900 #define PCIE_ATU_REGION_INBOUND BIT(31) #define PCIE_ATU_REGION_OUTBOUND 0 -#define PCIE_ATU_REGION_INDEX2 0x2 -#define PCIE_ATU_REGION_INDEX1 0x1 -#define PCIE_ATU_REGION_INDEX0 0x0 #define PCIE_ATU_CR1 0x904 #define PCIE_ATU_TYPE_MEM 0x0 #define PCIE_ATU_TYPE_IO 0x2 @@ -266,7 +263,6 @@ struct dw_pcie { /* Used when iatu_unroll_enabled is true */ void __iomem *atu_base; u32 num_viewport; - u8 iatu_unroll_enabled; struct pcie_port pp; struct dw_pcie_ep ep; const struct dw_pcie_ops *ops; @@ -274,6 +270,8 @@ struct dw_pcie { int num_lanes; int link_gen; u8 n_fts[2]; + bool iatu_unroll_enabled: 1; + bool io_cfg_atu_shared: 1; }; #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp) -- cgit v1.2.3 From fede8526cc4880d2a1ac4cfe357c299c4e1fd848 Mon Sep 17 00:00:00 2001 From: Vidya Sagar Date: Wed, 18 Nov 2020 20:16:25 +0530 Subject: PCI: of: Warn if non-prefetchable memory aperture size is > 32-bit As per PCIe spec r5.0, sec 7.5.1.3.8 only 32-bit BAR registers are defined for non-prefetchable memory and hence a warning should be reported when the size of them go beyond 32-bits. Link: https://lore.kernel.org/r/20201118144626.32189-2-vidyas@nvidia.com Tested-by: Thierry Reding Tested-by: Jon Hunter Signed-off-by: Vidya Sagar Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- drivers/pci/of.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/of.c b/drivers/pci/of.c index ac24cd5439a9..5ea472ae22ac 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -556,6 +556,11 @@ static int pci_parse_request_of_pci_ranges(struct device *dev, break; case IORESOURCE_MEM: res_valid |= !(res->flags & IORESOURCE_PREFETCH); + + if (!(res->flags & IORESOURCE_PREFETCH)) + if (upper_32_bits(resource_size(res))) + dev_warn(dev, "Memory resource size exceeds max for 32 bits\n"); + break; } } -- cgit v1.2.3 From 74081de4a1f70d14870c824a70e86aa0c1414945 Mon Sep 17 00:00:00 2001 From: Vidya Sagar Date: Wed, 18 Nov 2020 20:16:26 +0530 Subject: PCI: dwc: Add support to program ATU for >4GB memory Add support to program the ATU to enable translations for >4GB sizes of the prefetchable memory apertures. Link: https://lore.kernel.org/r/20201118144626.32189-3-vidyas@nvidia.com Tested-by: Thierry Reding Tested-by: Jon Hunter Signed-off-by: Vidya Sagar Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Acked-by: Jingoo --- drivers/pci/controller/dwc/pcie-designware.c | 12 +++++++----- drivers/pci/controller/dwc/pcie-designware.h | 3 ++- 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index c2dea8fc97c8..b5e438b70cd5 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -228,7 +228,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg, static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no, int index, int type, u64 cpu_addr, u64 pci_addr, - u32 size) + u64 size) { u32 retries, val; u64 limit_addr = cpu_addr + size - 1; @@ -245,8 +245,10 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no, lower_32_bits(pci_addr)); dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, upper_32_bits(pci_addr)); - dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, - type | PCIE_ATU_FUNC_NUM(func_no)); + val = type | PCIE_ATU_FUNC_NUM(func_no); + val = upper_32_bits(size - 1) ? + val | PCIE_ATU_INCREASE_REGION_SIZE : val; + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val); dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, PCIE_ATU_ENABLE); @@ -267,7 +269,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no, static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, int index, int type, u64 cpu_addr, - u64 pci_addr, u32 size) + u64 pci_addr, u64 size) { u32 retries, val; @@ -311,7 +313,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, } void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, - u64 cpu_addr, u64 pci_addr, u32 size) + u64 cpu_addr, u64 pci_addr, u64 size) { __dw_pcie_prog_outbound_atu(pci, 0, index, type, cpu_addr, pci_addr, size); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index ed19c34dd0fe..f9a20ce9ab9a 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -81,6 +81,7 @@ #define PCIE_ATU_REGION_INBOUND BIT(31) #define PCIE_ATU_REGION_OUTBOUND 0 #define PCIE_ATU_CR1 0x904 +#define PCIE_ATU_INCREASE_REGION_SIZE BIT(13) #define PCIE_ATU_TYPE_MEM 0x0 #define PCIE_ATU_TYPE_IO 0x2 #define PCIE_ATU_TYPE_CFG0 0x4 @@ -293,7 +294,7 @@ void dw_pcie_upconfig_setup(struct dw_pcie *pci); int dw_pcie_wait_for_link(struct dw_pcie *pci); void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, u64 cpu_addr, u64 pci_addr, - u32 size); + u64 size); void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index, int type, u64 cpu_addr, u64 pci_addr, u32 size); -- cgit v1.2.3 From 1d567aac46101c8743e49990b94560f86740bb1e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 5 Nov 2020 15:11:45 -0600 Subject: PCI: dwc/intel-gw: Move ATU offset out of driver match data The ATU offset should be a register range in DT called 'atu', not driver match data. Any future platforms with a different ATU offset should add it to their DT. This is also in preparation to do DBI resource setup in the core DWC code, so let's move setting atu_base later in intel_pcie_rc_setup(). Link: https://lore.kernel.org/r/20201105211159.1814485-3-robh@kernel.org Tested-by: Marek Szyprowski Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-intel-gw.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c index 5650cb78acba..77ef88333115 100644 --- a/drivers/pci/controller/dwc/pcie-intel-gw.c +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c @@ -58,7 +58,6 @@ struct intel_pcie_soc { unsigned int pcie_ver; - unsigned int pcie_atu_offset; u32 num_viewport; }; @@ -155,11 +154,15 @@ static void intel_pcie_init_n_fts(struct dw_pcie *pci) static void intel_pcie_rc_setup(struct intel_pcie_port *lpp) { + struct dw_pcie *pci = &lpp->pci; + + pci->atu_base = pci->dbi_base + 0xC0000; + intel_pcie_ltssm_disable(lpp); intel_pcie_link_setup(lpp); - intel_pcie_init_n_fts(&lpp->pci); - dw_pcie_setup_rc(&lpp->pci.pp); - dw_pcie_upconfig_setup(&lpp->pci); + intel_pcie_init_n_fts(pci); + dw_pcie_setup_rc(&pci->pp); + dw_pcie_upconfig_setup(pci); } static int intel_pcie_ep_rst_init(struct intel_pcie_port *lpp) @@ -425,7 +428,6 @@ static const struct dw_pcie_host_ops intel_pcie_dw_ops = { static const struct intel_pcie_soc pcie_data = { .pcie_ver = 0x520A, - .pcie_atu_offset = 0xC0000, .num_viewport = 3, }; @@ -461,7 +463,6 @@ static int intel_pcie_probe(struct platform_device *pdev) pci->ops = &intel_pcie_ops; pci->version = data->pcie_ver; - pci->atu_base = pci->dbi_base + data->pcie_atu_offset; pp->ops = &intel_pcie_dw_ops; ret = dw_pcie_host_init(pp); -- cgit v1.2.3 From a0fd361db8e508b8ce71c284b5ae3961759a0b3b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 5 Nov 2020 15:11:46 -0600 Subject: PCI: dwc: Move "dbi", "dbi2", and "addr_space" resource setup into common code Most DWC drivers use the common register resource names "dbi", "dbi2", and "addr_space", so let's move their setup into the DWC common code. This means 'dbi_base' in particular is setup later, but it looks like no drivers touch DBI registers before dw_pcie_host_init or dw_pcie_ep_init. Link: https://lore.kernel.org/r/20201105211159.1814485-4-robh@kernel.org Tested-by: Marek Szyprowski Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Acked-by: Jingoo Han Cc: Kishon Vijay Abraham I Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Murali Karicheri Cc: Minghuan Lian Cc: Mingkai Hu Cc: Roy Zang Cc: Jonathan Chocron Cc: Jesper Nilsson Cc: Gustavo Pimentel Cc: Xiaowei Song Cc: Binghui Wang Cc: Andy Gross Cc: Bjorn Andersson Cc: Stanimir Varbanov Cc: Pratyush Anand Cc: Thierry Reding Cc: Jonathan Hunter Cc: Kunihiko Hayashi Cc: Masahiro Yamada Cc: linux-omap@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-arm-kernel@axis.com Cc: linux-arm-msm@vger.kernel.org Cc: linux-tegra@vger.kernel.org --- drivers/pci/controller/dwc/pci-dra7xx.c | 8 ---- drivers/pci/controller/dwc/pci-keystone.c | 29 +-------------- drivers/pci/controller/dwc/pci-layerscape-ep.c | 37 +------------------ drivers/pci/controller/dwc/pcie-al.c | 9 +---- drivers/pci/controller/dwc/pcie-artpec6.c | 43 ++-------------------- drivers/pci/controller/dwc/pcie-designware-ep.c | 29 +++++++++++++-- drivers/pci/controller/dwc/pcie-designware-host.c | 7 ++++ drivers/pci/controller/dwc/pcie-designware-plat.c | 45 +---------------------- drivers/pci/controller/dwc/pcie-intel-gw.c | 4 -- drivers/pci/controller/dwc/pcie-kirin.c | 5 --- drivers/pci/controller/dwc/pcie-qcom.c | 8 ---- drivers/pci/controller/dwc/pcie-spear13xx.c | 11 +----- drivers/pci/controller/dwc/pcie-tegra194.c | 22 ----------- drivers/pci/controller/dwc/pcie-uniphier-ep.c | 38 +------------------ drivers/pci/controller/dwc/pcie-uniphier.c | 6 --- 15 files changed, 47 insertions(+), 254 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index 6d012d2b1e90..a4aabc85dbb1 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -578,7 +578,6 @@ static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx, { int ret; struct dw_pcie_ep *ep; - struct resource *res; struct device *dev = &pdev->dev; struct dw_pcie *pci = dra7xx->pci; @@ -594,13 +593,6 @@ static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx, if (IS_ERR(pci->dbi_base2)) return PTR_ERR(pci->dbi_base2); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); - if (!res) - return -EINVAL; - - ep->phys_base = res->start; - ep->addr_size = resource_size(res); - ret = dw_pcie_ep_init(ep); if (ret) { dev_err(dev, "failed to initialize endpoint\n"); diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index a222728238ca..9cf14f13798b 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -977,33 +977,6 @@ static const struct dw_pcie_ep_ops ks_pcie_am654_ep_ops = { .get_features = &ks_pcie_am654_get_features, }; -static int __init ks_pcie_add_pcie_ep(struct keystone_pcie *ks_pcie, - struct platform_device *pdev) -{ - int ret; - struct dw_pcie_ep *ep; - struct resource *res; - struct device *dev = &pdev->dev; - struct dw_pcie *pci = ks_pcie->pci; - - ep = &pci->ep; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); - if (!res) - return -EINVAL; - - ep->phys_base = res->start; - ep->addr_size = resource_size(res); - - ret = dw_pcie_ep_init(ep); - if (ret) { - dev_err(dev, "failed to initialize endpoint\n"); - return ret; - } - - return 0; -} - static void ks_pcie_disable_phy(struct keystone_pcie *ks_pcie) { int num_lanes = ks_pcie->num_lanes; @@ -1313,7 +1286,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) } pci->ep.ops = ep_ops; - ret = ks_pcie_add_pcie_ep(ks_pcie, pdev); + ret = dw_pcie_ep_init(&pci->ep); if (ret < 0) goto err_get_sync; break; diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index 84206f265e54..4d12efdacd2f 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -18,8 +18,6 @@ #include "pcie-designware.h" -#define PCIE_DBI2_OFFSET 0x1000 /* DBI2 base address*/ - #define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev) struct ls_pcie_ep_drvdata { @@ -124,34 +122,6 @@ static const struct of_device_id ls_pcie_ep_of_match[] = { { }, }; -static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie, - struct platform_device *pdev) -{ - struct dw_pcie *pci = pcie->pci; - struct device *dev = pci->dev; - struct dw_pcie_ep *ep; - struct resource *res; - int ret; - - ep = &pci->ep; - ep->ops = pcie->drvdata->ops; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); - if (!res) - return -EINVAL; - - ep->phys_base = res->start; - ep->addr_size = resource_size(res); - - ret = dw_pcie_ep_init(ep); - if (ret) { - dev_err(dev, "failed to initialize endpoint\n"); - return ret; - } - - return 0; -} - static int __init ls_pcie_ep_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -159,7 +129,6 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) struct ls_pcie_ep *pcie; struct pci_epc_features *ls_epc; struct resource *dbi_base; - int ret; pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); if (!pcie) @@ -188,13 +157,11 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) if (IS_ERR(pci->dbi_base)) return PTR_ERR(pci->dbi_base); - pci->dbi_base2 = pci->dbi_base + PCIE_DBI2_OFFSET; + pci->ep.ops = &ls_pcie_ep_ops; platform_set_drvdata(pdev, pcie); - ret = ls_add_pcie_ep(pcie, pdev); - - return ret; + return dw_pcie_ep_init(&pci->ep); } static struct platform_driver ls_pcie_ep_driver = { diff --git a/drivers/pci/controller/dwc/pcie-al.c b/drivers/pci/controller/dwc/pcie-al.c index f973fbca90cf..d06866921187 100644 --- a/drivers/pci/controller/dwc/pcie-al.c +++ b/drivers/pci/controller/dwc/pcie-al.c @@ -347,7 +347,6 @@ static int al_pcie_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct resource *controller_res; struct resource *ecam_res; - struct resource *dbi_res; struct al_pcie *al_pcie; struct dw_pcie *pci; @@ -365,11 +364,6 @@ static int al_pcie_probe(struct platform_device *pdev) al_pcie->pci = pci; al_pcie->dev = dev; - dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); - pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_res); - if (IS_ERR(pci->dbi_base)) - return PTR_ERR(pci->dbi_base); - ecam_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); if (!ecam_res) { dev_err(dev, "couldn't find 'config' reg in DT\n"); @@ -386,8 +380,7 @@ static int al_pcie_probe(struct platform_device *pdev) return PTR_ERR(al_pcie->controller_base); } - dev_dbg(dev, "From DT: dbi_base: %pR, controller_base: %pR\n", - dbi_res, controller_res); + dev_dbg(dev, "From DT: controller_base: %pR\n", controller_res); platform_set_drvdata(pdev, al_pcie); diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index 929448e9e0bc..52ad7909cd0c 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c @@ -403,38 +403,6 @@ static const struct dw_pcie_ep_ops pcie_ep_ops = { .raise_irq = artpec6_pcie_raise_irq, }; -static int artpec6_add_pcie_ep(struct artpec6_pcie *artpec6_pcie, - struct platform_device *pdev) -{ - int ret; - struct dw_pcie_ep *ep; - struct resource *res; - struct device *dev = &pdev->dev; - struct dw_pcie *pci = artpec6_pcie->pci; - - ep = &pci->ep; - ep->ops = &pcie_ep_ops; - - pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2"); - if (IS_ERR(pci->dbi_base2)) - return PTR_ERR(pci->dbi_base2); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); - if (!res) - return -EINVAL; - - ep->phys_base = res->start; - ep->addr_size = resource_size(res); - - ret = dw_pcie_ep_init(ep); - if (ret) { - dev_err(dev, "failed to initialize endpoint\n"); - return ret; - } - - return 0; -} - static int artpec6_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -469,10 +437,6 @@ static int artpec6_pcie_probe(struct platform_device *pdev) artpec6_pcie->variant = variant; artpec6_pcie->mode = mode; - pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi"); - if (IS_ERR(pci->dbi_base)) - return PTR_ERR(pci->dbi_base); - artpec6_pcie->phy_base = devm_platform_ioremap_resource_byname(pdev, "phy"); if (IS_ERR(artpec6_pcie->phy_base)) @@ -504,9 +468,10 @@ static int artpec6_pcie_probe(struct platform_device *pdev) val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); val &= ~PCIECFG_DEVICE_TYPE_MASK; artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); - ret = artpec6_add_pcie_ep(artpec6_pcie, pdev); - if (ret < 0) - return ret; + + pci->ep.ops = &pcie_ep_ops; + + return dw_pcie_ep_init(&pci->ep); break; } default: diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index ad7da4ea43a5..6fe176e1bdd2 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -7,6 +7,7 @@ */ #include +#include #include "pcie-designware.h" #include @@ -676,20 +677,42 @@ 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); - if (!pci->dbi_base || !pci->dbi_base2) { - dev_err(dev, "dbi_base/dbi_base2 is not populated\n"); - return -EINVAL; + if (!pci->dbi_base) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); + pci->dbi_base = devm_pci_remap_cfg_resource(dev, res); + if (IS_ERR(pci->dbi_base)) + return PTR_ERR(pci->dbi_base); + } + + if (!pci->dbi_base2) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi2"); + if (!res) + pci->dbi_base2 = pci->dbi_base + SZ_4K; + else { + pci->dbi_base2 = devm_pci_remap_cfg_resource(dev, res); + if (IS_ERR(pci->dbi_base2)) + return PTR_ERR(pci->dbi_base2); + } } + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); + if (!res) + return -EINVAL; + + ep->phys_base = res->start; + ep->addr_size = resource_size(res); + ret = of_property_read_u32(np, "num-ib-windows", &ep->num_ib_windows); if (ret < 0) { dev_err(dev, "Unable to read *num-ib-windows* property\n"); diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index a6ffab9b537e..cde45b2076ee 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -310,6 +310,13 @@ int dw_pcie_host_init(struct pcie_port *pp) dev_err(dev, "Missing *config* reg space\n"); } + if (!pci->dbi_base) { + struct resource *dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); + pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_res); + if (IS_ERR(pci->dbi_base)) + return PTR_ERR(pci->dbi_base); + } + bridge = devm_pci_alloc_host_bridge(dev, 0); if (!bridge) return -ENOMEM; diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index e3e300669ed5..562a05e07b1d 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -139,43 +139,11 @@ static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie, return 0; } -static int dw_plat_add_pcie_ep(struct dw_plat_pcie *dw_plat_pcie, - struct platform_device *pdev) -{ - int ret; - struct dw_pcie_ep *ep; - struct resource *res; - struct device *dev = &pdev->dev; - struct dw_pcie *pci = dw_plat_pcie->pci; - - ep = &pci->ep; - ep->ops = &pcie_ep_ops; - - pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2"); - if (IS_ERR(pci->dbi_base2)) - return PTR_ERR(pci->dbi_base2); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); - if (!res) - return -EINVAL; - - ep->phys_base = res->start; - ep->addr_size = resource_size(res); - - ret = dw_pcie_ep_init(ep); - if (ret) { - dev_err(dev, "Failed to initialize endpoint\n"); - return ret; - } - return 0; -} - static int dw_plat_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct dw_plat_pcie *dw_plat_pcie; struct dw_pcie *pci; - struct resource *res; /* Resource from DT */ int ret; const struct of_device_id *match; const struct dw_plat_pcie_of_data *data; @@ -202,14 +170,6 @@ static int dw_plat_pcie_probe(struct platform_device *pdev) dw_plat_pcie->pci = pci; dw_plat_pcie->mode = mode; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); - if (!res) - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - pci->dbi_base = devm_ioremap_resource(dev, res); - if (IS_ERR(pci->dbi_base)) - return PTR_ERR(pci->dbi_base); - platform_set_drvdata(pdev, dw_plat_pcie); switch (dw_plat_pcie->mode) { @@ -225,9 +185,8 @@ static int dw_plat_pcie_probe(struct platform_device *pdev) if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_EP)) return -ENODEV; - ret = dw_plat_add_pcie_ep(dw_plat_pcie, pdev); - if (ret < 0) - return ret; + pci->ep.ops = &pcie_ep_ops; + return dw_pcie_ep_init(&pci->ep); break; default: dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode); diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c index 77ef88333115..88782653ed21 100644 --- a/drivers/pci/controller/dwc/pcie-intel-gw.c +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c @@ -237,10 +237,6 @@ static int intel_pcie_get_resources(struct platform_device *pdev) struct device *dev = pci->dev; int ret; - pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi"); - if (IS_ERR(pci->dbi_base)) - return PTR_ERR(pci->dbi_base); - lpp->core_clk = devm_clk_get(dev, NULL); if (IS_ERR(lpp->core_clk)) { ret = PTR_ERR(lpp->core_clk); diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index d0a6a2dee6f5..3042a23cf09a 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c @@ -157,11 +157,6 @@ static long kirin_pcie_get_resource(struct kirin_pcie *kirin_pcie, if (IS_ERR(kirin_pcie->phy_base)) return PTR_ERR(kirin_pcie->phy_base); - kirin_pcie->pci->dbi_base = - devm_platform_ioremap_resource_byname(pdev, "dbi"); - if (IS_ERR(kirin_pcie->pci->dbi_base)) - return PTR_ERR(kirin_pcie->pci->dbi_base); - kirin_pcie->crgctrl = syscon_regmap_lookup_by_compatible("hisilicon,hi3660-crgctrl"); if (IS_ERR(kirin_pcie->crgctrl)) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index b4761640ffd9..3b4f70b9f3f0 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1368,7 +1368,6 @@ static const struct dw_pcie_ops dw_pcie_ops = { static int qcom_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct resource *res; struct pcie_port *pp; struct dw_pcie *pci; struct qcom_pcie *pcie; @@ -1407,13 +1406,6 @@ static int qcom_pcie_probe(struct platform_device *pdev) goto err_pm_runtime_put; } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); - pci->dbi_base = devm_pci_remap_cfg_resource(dev, res); - if (IS_ERR(pci->dbi_base)) { - ret = PTR_ERR(pci->dbi_base); - goto err_pm_runtime_put; - } - pcie->elbi = devm_platform_ioremap_resource_byname(pdev, "elbi"); if (IS_ERR(pcie->elbi)) { ret = PTR_ERR(pcie->elbi); diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c index e348225f651f..1ed7e3501ff1 100644 --- a/drivers/pci/controller/dwc/pcie-spear13xx.c +++ b/drivers/pci/controller/dwc/pcie-spear13xx.c @@ -152,6 +152,8 @@ static int spear13xx_pcie_host_init(struct pcie_port *pp) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pci); + spear13xx_pcie->app_base = pci->dbi_base + 0x2000; + spear13xx_pcie_establish_link(spear13xx_pcie); spear13xx_pcie_enable_interrupts(spear13xx_pcie); @@ -203,7 +205,6 @@ static int spear13xx_pcie_probe(struct platform_device *pdev) struct dw_pcie *pci; struct spear13xx_pcie *spear13xx_pcie; struct device_node *np = dev->of_node; - struct resource *dbi_base; int ret; spear13xx_pcie = devm_kzalloc(dev, sizeof(*spear13xx_pcie), GFP_KERNEL); @@ -242,14 +243,6 @@ static int spear13xx_pcie_probe(struct platform_device *pdev) return ret; } - dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); - pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base); - if (IS_ERR(pci->dbi_base)) { - ret = PTR_ERR(pci->dbi_base); - goto fail_clk; - } - spear13xx_pcie->app_base = pci->dbi_base + 0x2000; - if (of_property_read_bool(np, "st,pcie-is-gen1")) pci->link_gen = 1; diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index f920e7efe118..f8fca6794282 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1907,19 +1907,12 @@ static int tegra_pcie_config_ep(struct tegra_pcie_dw *pcie, struct dw_pcie *pci = &pcie->pci; struct device *dev = pcie->dev; struct dw_pcie_ep *ep; - struct resource *res; char *name; int ret; ep = &pci->ep; ep->ops = &pcie_ep_ops; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); - if (!res) - return -EINVAL; - - ep->phys_base = res->start; - ep->addr_size = resource_size(res); ep->page_size = SZ_64K; ret = gpiod_set_debounce(pcie->pex_rst_gpiod, PERST_DEBOUNCE_TIME); @@ -1982,7 +1975,6 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct resource *atu_dma_res; struct tegra_pcie_dw *pcie; - struct resource *dbi_res; struct pcie_port *pp; struct dw_pcie *pci; struct phy **phys; @@ -2091,20 +2083,6 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev) pcie->phys = phys; - dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); - if (!dbi_res) { - dev_err(dev, "Failed to find \"dbi\" region\n"); - return -ENODEV; - } - pcie->dbi_res = dbi_res; - - pci->dbi_base = devm_ioremap_resource(dev, dbi_res); - if (IS_ERR(pci->dbi_base)) - return PTR_ERR(pci->dbi_base); - - /* Tegra HW locates DBI2 at a fixed offset from DBI */ - pci->dbi_base2 = pci->dbi_base + 0x1000; - atu_dma_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "atu_dma"); if (!atu_dma_res) { diff --git a/drivers/pci/controller/dwc/pcie-uniphier-ep.c b/drivers/pci/controller/dwc/pcie-uniphier-ep.c index 148355960061..69810c6b0d58 100644 --- a/drivers/pci/controller/dwc/pcie-uniphier-ep.c +++ b/drivers/pci/controller/dwc/pcie-uniphier-ep.c @@ -218,35 +218,6 @@ static const struct dw_pcie_ep_ops uniphier_pcie_ep_ops = { .get_features = uniphier_pcie_get_features, }; -static int uniphier_add_pcie_ep(struct uniphier_pcie_ep_priv *priv, - struct platform_device *pdev) -{ - struct dw_pcie *pci = &priv->pci; - struct dw_pcie_ep *ep = &pci->ep; - struct device *dev = &pdev->dev; - struct resource *res; - int ret; - - ep->ops = &uniphier_pcie_ep_ops; - - pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2"); - if (IS_ERR(pci->dbi_base2)) - return PTR_ERR(pci->dbi_base2); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); - if (!res) - return -EINVAL; - - ep->phys_base = res->start; - ep->addr_size = resource_size(res); - - ret = dw_pcie_ep_init(ep); - if (ret) - dev_err(dev, "Failed to initialize endpoint (%d)\n", ret); - - return ret; -} - static int uniphier_pcie_ep_enable(struct uniphier_pcie_ep_priv *priv) { int ret; @@ -300,7 +271,6 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct uniphier_pcie_ep_priv *priv; - struct resource *res; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -314,11 +284,6 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev) priv->pci.dev = dev; priv->pci.ops = &dw_pcie_ops; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); - priv->pci.dbi_base = devm_pci_remap_cfg_resource(dev, res); - if (IS_ERR(priv->pci.dbi_base)) - return PTR_ERR(priv->pci.dbi_base); - priv->base = devm_platform_ioremap_resource_byname(pdev, "link"); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); @@ -352,7 +317,8 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev) if (ret) return ret; - return uniphier_add_pcie_ep(priv, pdev); + priv->pci.ep.ops = &uniphier_pcie_ep_ops; + return dw_pcie_ep_init(&priv->pci.ep); } static const struct pci_epc_features uniphier_pro5_data = { diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c index 48176265c867..33130fb4af90 100644 --- a/drivers/pci/controller/dwc/pcie-uniphier.c +++ b/drivers/pci/controller/dwc/pcie-uniphier.c @@ -400,7 +400,6 @@ static int uniphier_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct uniphier_pcie_priv *priv; - struct resource *res; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -410,11 +409,6 @@ static int uniphier_pcie_probe(struct platform_device *pdev) priv->pci.dev = dev; priv->pci.ops = &dw_pcie_ops; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); - priv->pci.dbi_base = devm_pci_remap_cfg_resource(dev, res); - if (IS_ERR(priv->pci.dbi_base)) - return PTR_ERR(priv->pci.dbi_base); - priv->base = devm_platform_ioremap_resource_byname(pdev, "link"); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); -- cgit v1.2.3 From 1cc9a559993a4a69e7bdfb24a2a75955d08cd542 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 5 Nov 2020 15:11:47 -0600 Subject: PCI: dwc/intel-gw: Remove some unneeded function wrappers Remove some of the pointless levels of functions that just wrap or group a series of other functions. Link: https://lore.kernel.org/r/20201105211159.1814485-5-robh@kernel.org Tested-by: Marek Szyprowski Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-intel-gw.c | 47 ++++++++++-------------------- 1 file changed, 16 insertions(+), 31 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c index 88782653ed21..c562eb7454b1 100644 --- a/drivers/pci/controller/dwc/pcie-intel-gw.c +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c @@ -152,19 +152,6 @@ static void intel_pcie_init_n_fts(struct dw_pcie *pci) pci->n_fts[0] = PORT_AFR_N_FTS_GEN12_DFT; } -static void intel_pcie_rc_setup(struct intel_pcie_port *lpp) -{ - struct dw_pcie *pci = &lpp->pci; - - pci->atu_base = pci->dbi_base + 0xC0000; - - intel_pcie_ltssm_disable(lpp); - intel_pcie_link_setup(lpp); - intel_pcie_init_n_fts(pci); - dw_pcie_setup_rc(&pci->pp); - dw_pcie_upconfig_setup(pci); -} - static int intel_pcie_ep_rst_init(struct intel_pcie_port *lpp) { struct device *dev = lpp->pci.dev; @@ -216,14 +203,6 @@ static void intel_pcie_device_rst_deassert(struct intel_pcie_port *lpp) gpiod_set_value_cansleep(lpp->reset_gpio, 0); } -static int intel_pcie_app_logic_setup(struct intel_pcie_port *lpp) -{ - intel_pcie_device_rst_deassert(lpp); - intel_pcie_ltssm_enable(lpp); - - return dw_pcie_wait_for_link(&lpp->pci); -} - static void intel_pcie_core_irq_disable(struct intel_pcie_port *lpp) { pcie_app_wr(lpp, PCIE_APP_IRNEN, 0); @@ -273,11 +252,6 @@ static int intel_pcie_get_resources(struct platform_device *pdev) return 0; } -static void intel_pcie_deinit_phy(struct intel_pcie_port *lpp) -{ - phy_exit(lpp->phy); -} - static int intel_pcie_wait_l2(struct intel_pcie_port *lpp) { u32 value; @@ -314,6 +288,7 @@ static void intel_pcie_turn_off(struct intel_pcie_port *lpp) static int intel_pcie_host_setup(struct intel_pcie_port *lpp) { int ret; + struct dw_pcie *pci = &lpp->pci; intel_pcie_core_rst_assert(lpp); intel_pcie_device_rst_assert(lpp); @@ -330,8 +305,18 @@ static int intel_pcie_host_setup(struct intel_pcie_port *lpp) goto clk_err; } - intel_pcie_rc_setup(lpp); - ret = intel_pcie_app_logic_setup(lpp); + pci->atu_base = pci->dbi_base + 0xC0000; + + intel_pcie_ltssm_disable(lpp); + intel_pcie_link_setup(lpp); + intel_pcie_init_n_fts(pci); + dw_pcie_setup_rc(&pci->pp); + dw_pcie_upconfig_setup(pci); + + intel_pcie_device_rst_deassert(lpp); + intel_pcie_ltssm_enable(lpp); + + ret = dw_pcie_wait_for_link(pci); if (ret) goto app_init_err; @@ -345,7 +330,7 @@ app_init_err: clk_disable_unprepare(lpp->core_clk); clk_err: intel_pcie_core_rst_assert(lpp); - intel_pcie_deinit_phy(lpp); + phy_exit(lpp->phy); return ret; } @@ -356,7 +341,7 @@ static void __intel_pcie_remove(struct intel_pcie_port *lpp) intel_pcie_turn_off(lpp); clk_disable_unprepare(lpp->core_clk); intel_pcie_core_rst_assert(lpp); - intel_pcie_deinit_phy(lpp); + phy_exit(lpp->phy); } static int intel_pcie_remove(struct platform_device *pdev) @@ -380,7 +365,7 @@ static int __maybe_unused intel_pcie_suspend_noirq(struct device *dev) if (ret) return ret; - intel_pcie_deinit_phy(lpp); + phy_exit(lpp->phy); clk_disable_unprepare(lpp->core_clk); return ret; } -- cgit v1.2.3 From 458ad06c4cddac4b85f70ee00c295e2c5127ff3c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 5 Nov 2020 15:11:48 -0600 Subject: PCI: dwc: Ensure all outbound ATU windows are reset The Layerscape driver clears the ATU registers which may have been configured by the bootloader. Any driver could have the same issue and doing it for all drivers doesn't hurt, so let's move it into the common DWC code. Link: https://lore.kernel.org/r/20201105211159.1814485-6-robh@kernel.org Tested-by: Marek Szyprowski Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Acked-by: Jingoo Han Cc: Minghuan Lian Cc: Mingkai Hu Cc: Roy Zang Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Jingoo Han Cc: Gustavo Pimentel Cc: linuxppc-dev@lists.ozlabs.org --- drivers/pci/controller/dwc/pci-layerscape.c | 14 -------------- drivers/pci/controller/dwc/pcie-designware-host.c | 5 +++++ 2 files changed, 5 insertions(+), 14 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index f24f79a70d9a..53e56d54c482 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -83,14 +83,6 @@ static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie) iowrite32(val, pci->dbi_base + PCIE_STRFMR1); } -static void ls_pcie_disable_outbound_atus(struct ls_pcie *pcie) -{ - int i; - - for (i = 0; i < PCIE_IATU_NUM; i++) - dw_pcie_disable_atu(pcie->pci, i, DW_PCIE_REGION_OUTBOUND); -} - static int ls1021_pcie_link_up(struct dw_pcie *pci) { u32 state; @@ -136,12 +128,6 @@ static int ls_pcie_host_init(struct pcie_port *pp) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct ls_pcie *pcie = to_ls_pcie(pci); - /* - * Disable outbound windows configured by the bootloader to avoid - * one transaction hitting multiple outbound windows. - * dw_pcie_setup_rc() will reconfigure the outbound windows. - */ - ls_pcie_disable_outbound_atus(pcie); ls_pcie_fix_error_response(pcie); dw_pcie_dbi_ro_wr_en(pci); diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index cde45b2076ee..265a48f1a0ae 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -534,6 +534,7 @@ static struct pci_ops dw_pcie_ops = { void dw_pcie_setup_rc(struct pcie_port *pp) { + int i; u32 val, ctrl, num_ctrls; struct dw_pcie *pci = to_dw_pcie_from_pp(pp); @@ -583,6 +584,10 @@ void dw_pcie_setup_rc(struct pcie_port *pp) PCI_COMMAND_MASTER | PCI_COMMAND_SERR; dw_pcie_writel_dbi(pci, PCI_COMMAND, val); + /* Ensure all outbound windows are disabled so there are multiple matches */ + for (i = 0; i < pci->num_viewport; i++) + dw_pcie_disable_atu(pci, i, DW_PCIE_REGION_OUTBOUND); + /* * If the platform provides its own child bus config accesses, it means * the platform uses its own address translation component rather than -- cgit v1.2.3 From 7f170d35f58311362e8b01b6774ca1053c0641b8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 5 Nov 2020 15:11:49 -0600 Subject: PCI: dwc/dra7xx: Use the common MSI irq_chip The dra7xx MSI irq_chip implementation is identical to the default DWC one. The only difference is the interrupt handler as the MSI interrupt is muxed with other interrupts, but that doesn't affect the irq_chip part of it. Link: https://lore.kernel.org/r/20201105211159.1814485-7-robh@kernel.org Tested-by: Marek Szyprowski Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Kishon Vijay Abraham I Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: linux-omap@vger.kernel.org --- drivers/pci/controller/dwc/pci-dra7xx.c | 125 -------------------------------- 1 file changed, 125 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index a4aabc85dbb1..4d0c35a4aa59 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -377,133 +377,8 @@ static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp) return 0; } -static void dra7xx_pcie_setup_msi_msg(struct irq_data *d, struct msi_msg *msg) -{ - struct pcie_port *pp = irq_data_get_irq_chip_data(d); - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - u64 msi_target; - - msi_target = (u64)pp->msi_data; - - msg->address_lo = lower_32_bits(msi_target); - msg->address_hi = upper_32_bits(msi_target); - - msg->data = d->hwirq; - - dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n", - (int)d->hwirq, msg->address_hi, msg->address_lo); -} - -static int dra7xx_pcie_msi_set_affinity(struct irq_data *d, - const struct cpumask *mask, - bool force) -{ - return -EINVAL; -} - -static void dra7xx_pcie_bottom_mask(struct irq_data *d) -{ - struct pcie_port *pp = irq_data_get_irq_chip_data(d); - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - unsigned int res, bit, ctrl; - unsigned long flags; - - raw_spin_lock_irqsave(&pp->lock, flags); - - ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL; - res = ctrl * MSI_REG_CTRL_BLOCK_SIZE; - bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL; - - pp->irq_mask[ctrl] |= BIT(bit); - dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res, - pp->irq_mask[ctrl]); - - raw_spin_unlock_irqrestore(&pp->lock, flags); -} - -static void dra7xx_pcie_bottom_unmask(struct irq_data *d) -{ - struct pcie_port *pp = irq_data_get_irq_chip_data(d); - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - unsigned int res, bit, ctrl; - unsigned long flags; - - raw_spin_lock_irqsave(&pp->lock, flags); - - ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL; - res = ctrl * MSI_REG_CTRL_BLOCK_SIZE; - bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL; - - pp->irq_mask[ctrl] &= ~BIT(bit); - dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res, - pp->irq_mask[ctrl]); - - raw_spin_unlock_irqrestore(&pp->lock, flags); -} - -static void dra7xx_pcie_bottom_ack(struct irq_data *d) -{ - struct pcie_port *pp = irq_data_get_irq_chip_data(d); - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - unsigned int res, bit, ctrl; - - ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL; - res = ctrl * MSI_REG_CTRL_BLOCK_SIZE; - bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL; - - dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_STATUS + res, BIT(bit)); -} - -static struct irq_chip dra7xx_pci_msi_bottom_irq_chip = { - .name = "DRA7XX-PCI-MSI", - .irq_ack = dra7xx_pcie_bottom_ack, - .irq_compose_msi_msg = dra7xx_pcie_setup_msi_msg, - .irq_set_affinity = dra7xx_pcie_msi_set_affinity, - .irq_mask = dra7xx_pcie_bottom_mask, - .irq_unmask = dra7xx_pcie_bottom_unmask, -}; - -static int dra7xx_pcie_msi_host_init(struct pcie_port *pp) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct device *dev = pci->dev; - u32 ctrl, num_ctrls; - int ret; - - pp->msi_irq_chip = &dra7xx_pci_msi_bottom_irq_chip; - - num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL; - /* Initialize IRQ Status array */ - for (ctrl = 0; ctrl < num_ctrls; ctrl++) { - pp->irq_mask[ctrl] = ~0; - dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + - (ctrl * MSI_REG_CTRL_BLOCK_SIZE), - pp->irq_mask[ctrl]); - dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_ENABLE + - (ctrl * MSI_REG_CTRL_BLOCK_SIZE), - ~0); - } - - ret = dw_pcie_allocate_domains(pp); - if (ret) - return ret; - - pp->msi_data = dma_map_single_attrs(dev, &pp->msi_msg, - sizeof(pp->msi_msg), - DMA_FROM_DEVICE, - DMA_ATTR_SKIP_CPU_SYNC); - ret = dma_mapping_error(dev, pp->msi_data); - if (ret) { - dev_err(dev, "Failed to map MSI data\n"); - pp->msi_data = 0; - dw_pcie_free_msi(pp); - } - return ret; -} - static const struct dw_pcie_host_ops dra7xx_pcie_host_ops = { .host_init = dra7xx_pcie_host_init, - .msi_host_init = dra7xx_pcie_msi_host_init, }; static void dra7xx_pcie_ep_init(struct dw_pcie_ep *ep) -- cgit v1.2.3 From 331e9bcead5252364e52fc95efbbe7273667b07d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 5 Nov 2020 15:11:50 -0600 Subject: PCI: dwc: Drop the .set_num_vectors() host op There's no reason for the .set_num_vectors() host op. Drivers needing a non-default value can just initialize pcie_port.num_vectors directly. Link: https://lore.kernel.org/r/20201105211159.1814485-8-robh@kernel.org Tested-by: Marek Szyprowski Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Acked-by: Jingoo Han Cc: Gustavo Pimentel Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Thierry Reding Cc: Jonathan Hunter Cc: linux-tegra@vger.kernel.org --- drivers/pci/controller/dwc/pcie-designware-host.c | 19 ++++--------------- drivers/pci/controller/dwc/pcie-designware-plat.c | 7 +------ drivers/pci/controller/dwc/pcie-designware.h | 1 - drivers/pci/controller/dwc/pcie-tegra194.c | 7 +------ 4 files changed, 6 insertions(+), 28 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 265a48f1a0ae..1bd6a9762426 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -365,22 +365,11 @@ int dw_pcie_host_init(struct pcie_port *pp) pci->link_gen = of_pci_get_max_link_speed(np); if (pci_msi_enabled()) { - /* - * If a specific SoC driver needs to change the - * default number of vectors, it needs to implement - * the set_num_vectors callback. - */ - if (!pp->ops->set_num_vectors) { + if (!pp->num_vectors) { pp->num_vectors = MSI_DEF_NUM_VECTORS; - } else { - pp->ops->set_num_vectors(pp); - - if (pp->num_vectors > MAX_MSI_IRQS || - pp->num_vectors == 0) { - dev_err(dev, - "Invalid number of vectors\n"); - return -EINVAL; - } + } else if (pp->num_vectors > MAX_MSI_IRQS) { + dev_err(dev, "Invalid number of vectors\n"); + return -EINVAL; } if (!pp->ops->msi_host_init) { diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index 562a05e07b1d..13fede1d4157 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -44,14 +44,8 @@ static int dw_plat_pcie_host_init(struct pcie_port *pp) return 0; } -static void dw_plat_set_num_vectors(struct pcie_port *pp) -{ - pp->num_vectors = MAX_MSI_IRQS; -} - static const struct dw_pcie_host_ops dw_plat_pcie_host_ops = { .host_init = dw_plat_pcie_host_init, - .set_num_vectors = dw_plat_set_num_vectors, }; static int dw_plat_pcie_establish_link(struct dw_pcie *pci) @@ -128,6 +122,7 @@ static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie, return pp->msi_irq; } + pp->num_vectors = MAX_MSI_IRQS; pp->ops = &dw_plat_pcie_host_ops; ret = dw_pcie_host_init(pp); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index f9a20ce9ab9a..41e739a73fbd 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -172,7 +172,6 @@ enum dw_pcie_device_mode { struct dw_pcie_host_ops { int (*host_init)(struct pcie_port *pp); - void (*set_num_vectors)(struct pcie_port *pp); int (*msi_host_init)(struct pcie_port *pp); }; diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index f8fca6794282..5e2841f58700 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -990,11 +990,6 @@ static int tegra_pcie_dw_link_up(struct dw_pcie *pci) return !!(val & PCI_EXP_LNKSTA_DLLLA); } -static void tegra_pcie_set_msi_vec_num(struct pcie_port *pp) -{ - pp->num_vectors = MAX_MSI_IRQS; -} - static int tegra_pcie_dw_start_link(struct dw_pcie *pci) { struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); @@ -1019,7 +1014,6 @@ static const struct dw_pcie_ops tegra_dw_pcie_ops = { static struct dw_pcie_host_ops tegra_pcie_dw_host_ops = { .host_init = tegra_pcie_dw_host_init, - .set_num_vectors = tegra_pcie_set_msi_vec_num, }; static void tegra_pcie_disable_phy(struct tegra_pcie_dw *pcie) @@ -1995,6 +1989,7 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev) pci->n_fts[1] = FTS_VAL; pp = &pci->pp; + pp->num_vectors = MAX_MSI_IRQS; pcie->dev = &pdev->dev; pcie->mode = (enum dw_pcie_device_mode)data->mode; -- cgit v1.2.3 From 5bcb1757e637a4f6d130f1f5106ce030516316b8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 5 Nov 2020 15:11:51 -0600 Subject: PCI: dwc: Move MSI interrupt setup into DWC common code Platforms using the built-in DWC MSI controller all have a dedicated interrupt with "msi" name or at index 0, so let's move setting up the interrupt to the common DWC code. spear13xx and dra7xx are the 2 oddballs with muxed interrupts, so we need to prevent configuring the MSI interrupt by setting msi_irq to negative. Link: https://lore.kernel.org/r/20201105211159.1814485-9-robh@kernel.org Tested-by: Marek Szyprowski Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Acked-by: Jingoo Han Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Kukjin Kim Cc: Krzysztof Kozlowski Cc: Richard Zhu Cc: Lucas Stach Cc: Shawn Guo Cc: Sascha Hauer Cc: Pengutronix Kernel Team Cc: Fabio Estevam Cc: NXP Linux Team Cc: Yue Wang Cc: Kevin Hilman Cc: Neil Armstrong Cc: Jerome Brunet Cc: Martin Blumenstingl Cc: Jesper Nilsson Cc: Gustavo Pimentel Cc: Xiaowei Song Cc: Binghui Wang Cc: Stanimir Varbanov Cc: Andy Gross Cc: Bjorn Andersson Cc: Pratyush Anand Cc: Thierry Reding Cc: Jonathan Hunter Cc: Kunihiko Hayashi Cc: Masahiro Yamada Cc: linux-samsung-soc@vger.kernel.org Cc: linux-amlogic@lists.infradead.org Cc: linux-arm-kernel@axis.com Cc: linux-arm-msm@vger.kernel.org Cc: linux-tegra@vger.kernel.org --- drivers/pci/controller/dwc/pci-dra7xx.c | 3 +++ drivers/pci/controller/dwc/pci-exynos.c | 6 ------ drivers/pci/controller/dwc/pci-imx6.c | 6 ------ drivers/pci/controller/dwc/pci-meson.c | 6 ------ drivers/pci/controller/dwc/pcie-artpec6.c | 6 ------ drivers/pci/controller/dwc/pcie-designware-host.c | 11 ++++++++++- drivers/pci/controller/dwc/pcie-designware-plat.c | 6 ------ drivers/pci/controller/dwc/pcie-histb.c | 6 ------ drivers/pci/controller/dwc/pcie-kirin.c | 22 ---------------------- drivers/pci/controller/dwc/pcie-qcom.c | 8 -------- drivers/pci/controller/dwc/pcie-spear13xx.c | 1 + drivers/pci/controller/dwc/pcie-tegra194.c | 8 -------- drivers/pci/controller/dwc/pcie-uniphier.c | 6 ------ 13 files changed, 14 insertions(+), 81 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index 4d0c35a4aa59..6b75c68dddb5 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -489,6 +489,9 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx, if (pp->irq < 0) return pp->irq; + /* MSI IRQ is muxed */ + pp->msi_irq = -ENODEV; + ret = dra7xx_pcie_init_irq_domain(pp); if (ret < 0) return ret; diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index 242683cde04a..7734394953e5 100644 --- a/drivers/pci/controller/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c @@ -415,12 +415,6 @@ static int __init exynos_add_pcie_port(struct exynos_pcie *ep, return ret; } - if (IS_ENABLED(CONFIG_PCI_MSI)) { - pp->msi_irq = platform_get_irq(pdev, 0); - if (pp->msi_irq < 0) - return pp->msi_irq; - } - pp->ops = &exynos_pcie_host_ops; ret = dw_pcie_host_init(pp); diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 5cf1ef12fb9b..95e7cf06863d 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -853,12 +853,6 @@ static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie, struct device *dev = &pdev->dev; int ret; - if (IS_ENABLED(CONFIG_PCI_MSI)) { - pp->msi_irq = platform_get_irq_byname(pdev, "msi"); - if (pp->msi_irq < 0) - return pp->msi_irq; - } - pp->ops = &imx6_pcie_host_ops; ret = dw_pcie_host_init(pp); diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index 1913dc2c8fa0..10d65b3093e4 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -405,12 +405,6 @@ static int meson_add_pcie_port(struct meson_pcie *mp, struct device *dev = &pdev->dev; int ret; - if (IS_ENABLED(CONFIG_PCI_MSI)) { - pp->msi_irq = platform_get_irq(pdev, 0); - if (pp->msi_irq < 0) - return pp->msi_irq; - } - pp->ops = &meson_pcie_host_ops; ret = dw_pcie_host_init(pp); diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index 52ad7909cd0c..a5239a58cee0 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c @@ -348,12 +348,6 @@ static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie, struct device *dev = pci->dev; int ret; - if (IS_ENABLED(CONFIG_PCI_MSI)) { - pp->msi_irq = platform_get_irq_byname(pdev, "msi"); - if (pp->msi_irq < 0) - return pp->msi_irq; - } - pp->ops = &artpec6_pcie_host_ops; ret = dw_pcie_host_init(pp); diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 1bd6a9762426..95deef0eaadf 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -373,13 +373,22 @@ int dw_pcie_host_init(struct pcie_port *pp) } if (!pp->ops->msi_host_init) { + if (!pp->msi_irq) { + pp->msi_irq = platform_get_irq_byname_optional(pdev, "msi"); + if (pp->msi_irq < 0) { + pp->msi_irq = platform_get_irq(pdev, 0); + if (pp->msi_irq < 0) + return pp->msi_irq; + } + } + pp->msi_irq_chip = &dw_pci_msi_bottom_irq_chip; ret = dw_pcie_allocate_domains(pp); if (ret) return ret; - if (pp->msi_irq) + if (pp->msi_irq > 0) irq_set_chained_handler_and_data(pp->msi_irq, dw_chained_msi_isr, pp); diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index 13fede1d4157..3da38ac6a87a 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -116,12 +116,6 @@ static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie, if (pp->irq < 0) return pp->irq; - if (IS_ENABLED(CONFIG_PCI_MSI)) { - pp->msi_irq = platform_get_irq(pdev, 0); - if (pp->msi_irq < 0) - return pp->msi_irq; - } - pp->num_vectors = MAX_MSI_IRQS; pp->ops = &dw_plat_pcie_host_ops; diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c index afc1abbe49aa..777e24902afb 100644 --- a/drivers/pci/controller/dwc/pcie-histb.c +++ b/drivers/pci/controller/dwc/pcie-histb.c @@ -400,12 +400,6 @@ static int histb_pcie_probe(struct platform_device *pdev) return PTR_ERR(hipcie->bus_reset); } - if (IS_ENABLED(CONFIG_PCI_MSI)) { - pp->msi_irq = platform_get_irq_byname(pdev, "msi"); - if (pp->msi_irq < 0) - return pp->msi_irq; - } - hipcie->phy = devm_phy_get(dev, "phy"); if (IS_ERR(hipcie->phy)) { dev_info(dev, "no pcie-phy found\n"); diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index 3042a23cf09a..ba03dbca7885 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c @@ -439,31 +439,9 @@ static const struct dw_pcie_host_ops kirin_pcie_host_ops = { .host_init = kirin_pcie_host_init, }; -static int kirin_pcie_add_msi(struct dw_pcie *pci, - struct platform_device *pdev) -{ - int irq; - - if (IS_ENABLED(CONFIG_PCI_MSI)) { - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - - pci->pp.msi_irq = irq; - } - - return 0; -} - static int kirin_add_pcie_port(struct dw_pcie *pci, struct platform_device *pdev) { - int ret; - - ret = kirin_pcie_add_msi(pci, pdev); - if (ret) - return ret; - pci->pp.ops = &kirin_pcie_host_ops; return dw_pcie_host_init(&pci->pp); diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 3b4f70b9f3f0..7ac08f0cae17 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1424,14 +1424,6 @@ static int qcom_pcie_probe(struct platform_device *pdev) pp->ops = &qcom_pcie_dw_ops; - if (IS_ENABLED(CONFIG_PCI_MSI)) { - pp->msi_irq = platform_get_irq_byname(pdev, "msi"); - if (pp->msi_irq < 0) { - ret = pp->msi_irq; - goto err_pm_runtime_put; - } - } - ret = phy_init(pcie->phy); if (ret) { pm_runtime_disable(&pdev->dev); diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c index 1ed7e3501ff1..800c34a60a33 100644 --- a/drivers/pci/controller/dwc/pcie-spear13xx.c +++ b/drivers/pci/controller/dwc/pcie-spear13xx.c @@ -185,6 +185,7 @@ static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie, } pp->ops = &spear13xx_pcie_host_ops; + pp->msi_irq = -ENODEV; ret = dw_pcie_host_init(pp); if (ret) { diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 5e2841f58700..77fc3ba3dec1 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1554,14 +1554,6 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie) char *name; int ret; - if (IS_ENABLED(CONFIG_PCI_MSI)) { - pp->msi_irq = of_irq_get_byname(dev->of_node, "msi"); - if (!pp->msi_irq) { - dev_err(dev, "Failed to get MSI interrupt\n"); - return -ENODEV; - } - } - pm_runtime_enable(dev); ret = pm_runtime_get_sync(dev); diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c index 33130fb4af90..6198bd106b8a 100644 --- a/drivers/pci/controller/dwc/pcie-uniphier.c +++ b/drivers/pci/controller/dwc/pcie-uniphier.c @@ -341,12 +341,6 @@ static int uniphier_add_pcie_port(struct uniphier_pcie_priv *priv, pp->ops = &uniphier_pcie_host_ops; - if (IS_ENABLED(CONFIG_PCI_MSI)) { - pp->msi_irq = platform_get_irq_byname(pdev, "msi"); - if (pp->msi_irq < 0) - return pp->msi_irq; - } - ret = dw_pcie_host_init(pp); if (ret) { dev_err(dev, "Failed to initialize host (%d)\n", ret); -- cgit v1.2.3 From f78f02638af5941eb45a402fa52c0edf4ac0f507 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 5 Nov 2020 15:11:52 -0600 Subject: PCI: dwc: Rework MSI initialization There are 3 possible MSI implementations for the DWC host. The first is using the built-in DWC MSI controller. The 2nd is a custom MSI controller as part of the PCI host (keystone only). The 3rd is an external MSI controller (typically GICv3 ITS). Currently, the last 2 are distinguished with a .msi_host_init() hook with the 3rd option using an empty function. However we can detect the 3rd case with the presence of 'msi-parent' or 'msi-map' properties, so let's do that instead and remove the empty functions. Link: https://lore.kernel.org/r/20201105211159.1814485-10-robh@kernel.org Tested-by: Marek Szyprowski Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Acked-by: Jingoo Han Cc: Murali Karicheri Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Minghuan Lian Cc: Mingkai Hu Cc: Roy Zang Cc: Gustavo Pimentel Cc: linuxppc-dev@lists.ozlabs.org --- drivers/pci/controller/dwc/pci-keystone.c | 9 -------- drivers/pci/controller/dwc/pci-layerscape.c | 25 ----------------------- drivers/pci/controller/dwc/pcie-designware-host.c | 20 ++++++++++-------- drivers/pci/controller/dwc/pcie-designware.h | 1 + drivers/pci/controller/dwc/pcie-intel-gw.c | 9 -------- 5 files changed, 13 insertions(+), 51 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 9cf14f13798b..784385ae6074 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -272,14 +272,6 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, ks_pcie_app_writel(ks_pcie, IRQ_EOI, offset); } -/* - * Dummy function so that DW core doesn't configure MSI - */ -static int ks_pcie_am654_msi_host_init(struct pcie_port *pp) -{ - return 0; -} - static void ks_pcie_enable_error_irq(struct keystone_pcie *ks_pcie) { ks_pcie_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL); @@ -854,7 +846,6 @@ static const struct dw_pcie_host_ops ks_pcie_host_ops = { static const struct dw_pcie_host_ops ks_pcie_am654_host_ops = { .host_init = ks_pcie_host_init, - .msi_host_init = ks_pcie_am654_msi_host_init, }; static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv) diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index 53e56d54c482..0d84986c4c16 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -168,37 +168,12 @@ static int ls1021_pcie_host_init(struct pcie_port *pp) return ls_pcie_host_init(pp); } -static int ls_pcie_msi_host_init(struct pcie_port *pp) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct device *dev = pci->dev; - struct device_node *np = dev->of_node; - struct device_node *msi_node; - - /* - * The MSI domain is set by the generic of_msi_configure(). This - * .msi_host_init() function keeps us from doing the default MSI - * domain setup in dw_pcie_host_init() and also enforces the - * requirement that "msi-parent" exists. - */ - msi_node = of_parse_phandle(np, "msi-parent", 0); - if (!msi_node) { - dev_err(dev, "failed to find msi-parent\n"); - return -EINVAL; - } - - of_node_put(msi_node); - return 0; -} - static const struct dw_pcie_host_ops ls1021_pcie_host_ops = { .host_init = ls1021_pcie_host_init, - .msi_host_init = ls_pcie_msi_host_init, }; static const struct dw_pcie_host_ops ls_pcie_host_ops = { .host_init = ls_pcie_host_init, - .msi_host_init = ls_pcie_msi_host_init, }; static const struct dw_pcie_ops dw_ls1021_pcie_ops = { diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 95deef0eaadf..9b952639d020 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -365,6 +365,10 @@ int dw_pcie_host_init(struct pcie_port *pp) pci->link_gen = of_pci_get_max_link_speed(np); if (pci_msi_enabled()) { + pp->has_msi_ctrl = !(pp->ops->msi_host_init || + of_property_read_bool(np, "msi-parent") || + of_property_read_bool(np, "msi-map")); + if (!pp->num_vectors) { pp->num_vectors = MSI_DEF_NUM_VECTORS; } else if (pp->num_vectors > MAX_MSI_IRQS) { @@ -372,7 +376,11 @@ int dw_pcie_host_init(struct pcie_port *pp) return -EINVAL; } - if (!pp->ops->msi_host_init) { + if (pp->ops->msi_host_init) { + ret = pp->ops->msi_host_init(pp); + if (ret < 0) + return ret; + } else if (pp->has_msi_ctrl) { if (!pp->msi_irq) { pp->msi_irq = platform_get_irq_byname_optional(pdev, "msi"); if (pp->msi_irq < 0) { @@ -402,10 +410,6 @@ int dw_pcie_host_init(struct pcie_port *pp) pp->msi_data = 0; goto err_free_msi; } - } else { - ret = pp->ops->msi_host_init(pp); - if (ret < 0) - return ret; } } @@ -426,7 +430,7 @@ int dw_pcie_host_init(struct pcie_port *pp) return 0; err_free_msi: - if (pci_msi_enabled() && !pp->ops->msi_host_init) + if (pp->has_msi_ctrl) dw_pcie_free_msi(pp); return ret; } @@ -436,7 +440,7 @@ void dw_pcie_host_deinit(struct pcie_port *pp) { pci_stop_root_bus(pp->bridge->bus); pci_remove_root_bus(pp->bridge->bus); - if (pci_msi_enabled() && !pp->ops->msi_host_init) + if (pp->has_msi_ctrl) dw_pcie_free_msi(pp); } EXPORT_SYMBOL_GPL(dw_pcie_host_deinit); @@ -544,7 +548,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp) dw_pcie_setup(pci); - if (pci_msi_enabled() && !pp->ops->msi_host_init) { + if (pp->has_msi_ctrl) { num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL; /* Initialize IRQ Status array */ diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 41e739a73fbd..a6ef286000a6 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -176,6 +176,7 @@ struct dw_pcie_host_ops { }; struct pcie_port { + bool has_msi_ctrl:1; u64 cfg0_base; void __iomem *va_cfg0_base; u32 cfg0_size; diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c index c562eb7454b1..292b9de86532 100644 --- a/drivers/pci/controller/dwc/pcie-intel-gw.c +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c @@ -385,14 +385,6 @@ static int intel_pcie_rc_init(struct pcie_port *pp) return intel_pcie_host_setup(lpp); } -/* - * Dummy function so that DW core doesn't configure MSI - */ -static int intel_pcie_msi_init(struct pcie_port *pp) -{ - return 0; -} - static u64 intel_pcie_cpu_addr(struct dw_pcie *pcie, u64 cpu_addr) { return cpu_addr + BUS_IATU_OFFSET; @@ -404,7 +396,6 @@ static const struct dw_pcie_ops intel_pcie_ops = { static const struct dw_pcie_host_ops intel_pcie_dw_ops = { .host_init = intel_pcie_rc_init, - .msi_host_init = intel_pcie_msi_init, }; static const struct intel_pcie_soc pcie_data = { -- cgit v1.2.3 From 886a9c1347558f0568e87fbbe7bcc3a76102bf0b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 5 Nov 2020 15:11:53 -0600 Subject: PCI: dwc: Move link handling into common code All the DWC drivers do link setup and checks at roughly the same time. Let's use the existing .start_link() hook (currently only used in EP mode) and move the link handling to the core code. The behavior for a link down was inconsistent as some drivers would fail probe in that case while others succeed. Let's standardize this to succeed as there are usecases where devices (and the link) appear later even without hotplug. For example, a reconfigured FPGA device. Link: https://lore.kernel.org/r/20201105211159.1814485-11-robh@kernel.org Tested-by: Marek Szyprowski Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Acked-by: Jingoo Han Cc: Kishon Vijay Abraham I Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Kukjin Kim Cc: Krzysztof Kozlowski Cc: Richard Zhu Cc: Lucas Stach Cc: Shawn Guo Cc: Sascha Hauer Cc: Pengutronix Kernel Team Cc: Fabio Estevam Cc: NXP Linux Team Cc: Murali Karicheri Cc: Yue Wang Cc: Kevin Hilman Cc: Neil Armstrong Cc: Jerome Brunet Cc: Martin Blumenstingl Cc: Thomas Petazzoni Cc: Jesper Nilsson Cc: Gustavo Pimentel Cc: Xiaowei Song Cc: Binghui Wang Cc: Andy Gross Cc: Bjorn Andersson Cc: Stanimir Varbanov Cc: Pratyush Anand Cc: Thierry Reding Cc: Jonathan Hunter Cc: Kunihiko Hayashi Cc: Masahiro Yamada Cc: linux-omap@vger.kernel.org Cc: linux-samsung-soc@vger.kernel.org Cc: linux-amlogic@lists.infradead.org Cc: linux-arm-kernel@axis.com Cc: linux-arm-msm@vger.kernel.org Cc: linux-tegra@vger.kernel.org --- drivers/pci/controller/dwc/pci-dra7xx.c | 2 - drivers/pci/controller/dwc/pci-exynos.c | 41 +++++++++----------- drivers/pci/controller/dwc/pci-imx6.c | 9 ++--- drivers/pci/controller/dwc/pci-keystone.c | 9 ----- drivers/pci/controller/dwc/pci-meson.c | 24 +++++------- drivers/pci/controller/dwc/pcie-armada8k.c | 39 +++++++++---------- drivers/pci/controller/dwc/pcie-artpec6.c | 2 - drivers/pci/controller/dwc/pcie-designware-host.c | 9 +++++ drivers/pci/controller/dwc/pcie-designware-plat.c | 3 -- drivers/pci/controller/dwc/pcie-histb.c | 34 ++++++++--------- drivers/pci/controller/dwc/pcie-kirin.c | 23 ++---------- drivers/pci/controller/dwc/pcie-qcom.c | 19 +++------- drivers/pci/controller/dwc/pcie-spear13xx.c | 46 ++++++++++------------- drivers/pci/controller/dwc/pcie-tegra194.c | 1 - drivers/pci/controller/dwc/pcie-uniphier.c | 13 ++----- 15 files changed, 103 insertions(+), 171 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index 6b75c68dddb5..054423d9646d 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -183,8 +183,6 @@ static int dra7xx_pcie_host_init(struct pcie_port *pp) dw_pcie_setup_rc(pp); - dra7xx_pcie_establish_link(pci); - dw_pcie_wait_for_link(pci); dw_pcie_msi_init(pp); dra7xx_pcie_enable_interrupts(dra7xx); diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index 7734394953e5..6498b615c834 100644 --- a/drivers/pci/controller/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c @@ -229,30 +229,9 @@ static void exynos_pcie_assert_reset(struct exynos_pcie *ep) GPIOF_OUT_INIT_HIGH, "RESET"); } -static int exynos_pcie_establish_link(struct exynos_pcie *ep) +static int exynos_pcie_start_link(struct dw_pcie *pci) { - struct dw_pcie *pci = ep->pci; - struct pcie_port *pp = &pci->pp; - struct device *dev = pci->dev; - - if (dw_pcie_link_up(pci)) { - dev_err(dev, "Link already up\n"); - return 0; - } - - exynos_pcie_assert_core_reset(ep); - - phy_reset(ep->phy); - - exynos_pcie_writel(ep->mem_res->elbi_base, 1, - PCIE_PWR_RESET); - - phy_power_on(ep->phy); - phy_init(ep->phy); - - exynos_pcie_deassert_core_reset(ep); - dw_pcie_setup_rc(pp); - exynos_pcie_assert_reset(ep); + struct exynos_pcie *ep = to_exynos_pcie(pci); /* assert LTSSM enable */ exynos_pcie_writel(ep->mem_res->elbi_base, PCIE_ELBI_LTSSM_ENABLE, @@ -386,7 +365,20 @@ static int exynos_pcie_host_init(struct pcie_port *pp) pp->bridge->ops = &exynos_pci_ops; - exynos_pcie_establish_link(ep); + exynos_pcie_assert_core_reset(ep); + + phy_reset(ep->phy); + + exynos_pcie_writel(ep->mem_res->elbi_base, 1, + PCIE_PWR_RESET); + + phy_power_on(ep->phy); + phy_init(ep->phy); + + exynos_pcie_deassert_core_reset(ep); + dw_pcie_setup_rc(pp); + exynos_pcie_assert_reset(ep); + exynos_pcie_enable_interrupts(ep); return 0; @@ -430,6 +422,7 @@ static const struct dw_pcie_ops dw_pcie_ops = { .read_dbi = exynos_pcie_read_dbi, .write_dbi = exynos_pcie_write_dbi, .link_up = exynos_pcie_link_up, + .start_link = exynos_pcie_start_link, }; static int __init exynos_pcie_probe(struct platform_device *pdev) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 95e7cf06863d..1fe8f3f2c380 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -745,9 +745,9 @@ static void imx6_pcie_ltssm_enable(struct device *dev) } } -static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) +static int imx6_pcie_start_link(struct dw_pcie *pci) { - struct dw_pcie *pci = imx6_pcie->pci; + struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci); struct device *dev = pci->dev; u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); u32 tmp; @@ -835,7 +835,6 @@ static int imx6_pcie_host_init(struct pcie_port *pp) imx6_pcie_deassert_core_reset(imx6_pcie); imx6_setup_phy_mpll(imx6_pcie); dw_pcie_setup_rc(pp); - imx6_pcie_establish_link(imx6_pcie); dw_pcie_msi_init(pp); return 0; @@ -865,7 +864,7 @@ static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie, } static const struct dw_pcie_ops dw_pcie_ops = { - /* No special ops needed, but pcie-designware still expects this struct */ + .start_link = imx6_pcie_start_link, }; #ifdef CONFIG_PM_SLEEP @@ -974,7 +973,7 @@ static int imx6_pcie_resume_noirq(struct device *dev) imx6_pcie_deassert_core_reset(imx6_pcie); dw_pcie_setup_rc(pp); - ret = imx6_pcie_establish_link(imx6_pcie); + ret = imx6_pcie_start_link(imx6_pcie->pci); if (ret < 0) dev_info(dev, "pcie link is down after resume.\n"); diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 784385ae6074..90b222b020a3 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -511,14 +511,8 @@ static void ks_pcie_stop_link(struct dw_pcie *pci) static int ks_pcie_start_link(struct dw_pcie *pci) { struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - struct device *dev = pci->dev; u32 val; - if (dw_pcie_link_up(pci)) { - dev_dbg(dev, "link is already up\n"); - return 0; - } - /* Initiate Link Training */ val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); @@ -833,9 +827,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) "Asynchronous external abort"); #endif - ks_pcie_start_link(pci); - dw_pcie_wait_for_link(pci); - return 0; } diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index 10d65b3093e4..41a3351b100b 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -231,7 +231,7 @@ static void meson_pcie_assert_reset(struct meson_pcie *mp) gpiod_set_value_cansleep(mp->reset_gpio, 0); } -static void meson_pcie_init_dw(struct meson_pcie *mp) +static void meson_pcie_ltssm_enable(struct meson_pcie *mp) { u32 val; @@ -289,20 +289,14 @@ static void meson_set_max_rd_req_size(struct meson_pcie *mp, int size) dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val); } -static int meson_pcie_establish_link(struct meson_pcie *mp) +static int meson_pcie_start_link(struct dw_pcie *pci) { - struct dw_pcie *pci = &mp->pci; - struct pcie_port *pp = &pci->pp; - - meson_pcie_init_dw(mp); - meson_set_max_payload(mp, MAX_PAYLOAD_SIZE); - meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE); - - dw_pcie_setup_rc(pp); + struct meson_pcie *mp = to_meson_pcie(pci); + meson_pcie_ltssm_enable(mp); meson_pcie_assert_reset(mp); - return dw_pcie_wait_for_link(pci); + return 0; } static int meson_pcie_rd_own_conf(struct pci_bus *bus, u32 devfn, @@ -380,14 +374,13 @@ static int meson_pcie_host_init(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct meson_pcie *mp = to_meson_pcie(pci); - int ret; pp->bridge->ops = &meson_pci_ops; - ret = meson_pcie_establish_link(mp); - if (ret) - return ret; + meson_set_max_payload(mp, MAX_PAYLOAD_SIZE); + meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE); + dw_pcie_setup_rc(pp); dw_pcie_msi_init(pp); return 0; @@ -418,6 +411,7 @@ static int meson_add_pcie_port(struct meson_pcie *mp, static const struct dw_pcie_ops dw_pcie_ops = { .link_up = meson_pcie_link_up, + .start_link = meson_pcie_start_link, }; static int meson_pcie_probe(struct platform_device *pdev) diff --git a/drivers/pci/controller/dwc/pcie-armada8k.c b/drivers/pci/controller/dwc/pcie-armada8k.c index 13901f359a41..dd2926bbb901 100644 --- a/drivers/pci/controller/dwc/pcie-armada8k.c +++ b/drivers/pci/controller/dwc/pcie-armada8k.c @@ -154,10 +154,24 @@ static int armada8k_pcie_link_up(struct dw_pcie *pci) return 0; } -static void armada8k_pcie_establish_link(struct armada8k_pcie *pcie) +static int armada8k_pcie_start_link(struct dw_pcie *pci) +{ + u32 reg; + + /* Start LTSSM */ + reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG); + reg |= PCIE_APP_LTSSM_EN; + dw_pcie_writel_dbi(pci, PCIE_GLOBAL_CONTROL_REG, reg); + + return 0; +} + +static int armada8k_pcie_host_init(struct pcie_port *pp) { - struct dw_pcie *pci = pcie->pci; u32 reg; + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + + dw_pcie_setup_rc(pp); if (!dw_pcie_link_up(pci)) { /* Disable LTSSM state machine to enable configuration */ @@ -193,26 +207,6 @@ static void armada8k_pcie_establish_link(struct armada8k_pcie *pcie) PCIE_INT_C_ASSERT_MASK | PCIE_INT_D_ASSERT_MASK; dw_pcie_writel_dbi(pci, PCIE_GLOBAL_INT_MASK1_REG, reg); - if (!dw_pcie_link_up(pci)) { - /* Configuration done. Start LTSSM */ - reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG); - reg |= PCIE_APP_LTSSM_EN; - dw_pcie_writel_dbi(pci, PCIE_GLOBAL_CONTROL_REG, reg); - } - - /* Wait until the link becomes active again */ - if (dw_pcie_wait_for_link(pci)) - dev_err(pci->dev, "Link not up after reconfiguration\n"); -} - -static int armada8k_pcie_host_init(struct pcie_port *pp) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct armada8k_pcie *pcie = to_armada8k_pcie(pci); - - dw_pcie_setup_rc(pp); - armada8k_pcie_establish_link(pcie); - return 0; } @@ -269,6 +263,7 @@ static int armada8k_add_pcie_port(struct armada8k_pcie *pcie, static const struct dw_pcie_ops dw_pcie_ops = { .link_up = armada8k_pcie_link_up, + .start_link = armada8k_pcie_start_link, }; static int armada8k_pcie_probe(struct platform_device *pdev) diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index a5239a58cee0..8b3da3038ac3 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c @@ -329,8 +329,6 @@ static int artpec6_pcie_host_init(struct pcie_port *pp) artpec6_pcie_deassert_core_reset(artpec6_pcie); artpec6_pcie_wait_for_phy(artpec6_pcie); dw_pcie_setup_rc(pp); - artpec6_pcie_establish_link(pci); - dw_pcie_wait_for_link(pci); dw_pcie_msi_init(pp); return 0; diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 9b952639d020..800e7a0415cf 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -423,6 +423,15 @@ int dw_pcie_host_init(struct pcie_port *pp) goto err_free_msi; } + if (!dw_pcie_link_up(pci) && pci->ops->start_link) { + ret = pci->ops->start_link(pci); + if (ret) + goto err_free_msi; + } + + /* Ignore errors, the link may come up later */ + dw_pcie_wait_for_link(pci); + bridge->sysdata = pp; ret = pci_host_probe(bridge); diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index 3da38ac6a87a..adebcaeb1a6c 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -35,10 +35,7 @@ static const struct of_device_id dw_plat_pcie_of_match[]; static int dw_plat_pcie_host_init(struct pcie_port *pp) { - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - dw_pcie_setup_rc(pp); - dw_pcie_wait_for_link(pci); dw_pcie_msi_init(pp); return 0; diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c index 777e24902afb..ece544165059 100644 --- a/drivers/pci/controller/dwc/pcie-histb.c +++ b/drivers/pci/controller/dwc/pcie-histb.c @@ -169,39 +169,36 @@ static int histb_pcie_link_up(struct dw_pcie *pci) return 0; } -static int histb_pcie_establish_link(struct pcie_port *pp) +static int histb_pcie_start_link(struct dw_pcie *pci) { - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct histb_pcie *hipcie = to_histb_pcie(pci); u32 regval; - if (dw_pcie_link_up(pci)) { - dev_info(pci->dev, "Link already up\n"); - return 0; - } - - /* PCIe RC work mode */ - regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL0); - regval &= ~PCIE_DEVICE_TYPE_MASK; - regval |= PCIE_WM_RC; - histb_pcie_writel(hipcie, PCIE_SYS_CTRL0, regval); - - /* setup root complex */ - dw_pcie_setup_rc(pp); - /* assert LTSSM enable */ regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL7); regval |= PCIE_APP_LTSSM_ENABLE; histb_pcie_writel(hipcie, PCIE_SYS_CTRL7, regval); - return dw_pcie_wait_for_link(pci); + return 0; } static int histb_pcie_host_init(struct pcie_port *pp) { + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct histb_pcie *hipcie = to_histb_pcie(pci); + u32 regval; + pp->bridge->ops = &histb_pci_ops; - histb_pcie_establish_link(pp); + /* PCIe RC work mode */ + regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL0); + regval &= ~PCIE_DEVICE_TYPE_MASK; + regval |= PCIE_WM_RC; + histb_pcie_writel(hipcie, PCIE_SYS_CTRL0, regval); + + /* setup root complex */ + dw_pcie_setup_rc(pp); + dw_pcie_msi_init(pp); return 0; @@ -300,6 +297,7 @@ static const struct dw_pcie_ops dw_pcie_ops = { .read_dbi = histb_pcie_read_dbi, .write_dbi = histb_pcie_write_dbi, .link_up = histb_pcie_link_up, + .start_link = histb_pcie_start_link, }; static int histb_pcie_probe(struct platform_device *pdev) diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index ba03dbca7885..675b4d8392d3 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c @@ -390,32 +390,14 @@ static int kirin_pcie_link_up(struct dw_pcie *pci) return 0; } -static int kirin_pcie_establish_link(struct pcie_port *pp) +static int kirin_pcie_start_link(struct dw_pcie *pci) { - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci); - struct device *dev = kirin_pcie->pci->dev; - int count = 0; - - if (kirin_pcie_link_up(pci)) - return 0; - - dw_pcie_setup_rc(pp); /* assert LTSSM enable */ kirin_apb_ctrl_writel(kirin_pcie, PCIE_LTSSM_ENABLE_BIT, PCIE_APP_LTSSM_ENABLE); - /* check if the link is up or not */ - while (!kirin_pcie_link_up(pci)) { - usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX); - count++; - if (count == 1000) { - dev_err(dev, "Link Fail\n"); - return -EINVAL; - } - } - return 0; } @@ -423,7 +405,7 @@ static int kirin_pcie_host_init(struct pcie_port *pp) { pp->bridge->ops = &kirin_pci_ops; - kirin_pcie_establish_link(pp); + dw_pcie_setup_rc(pp); dw_pcie_msi_init(pp); return 0; @@ -433,6 +415,7 @@ static const struct dw_pcie_ops kirin_dw_pcie_ops = { .read_dbi = kirin_pcie_read_dbi, .write_dbi = kirin_pcie_write_dbi, .link_up = kirin_pcie_link_up, + .start_link = kirin_pcie_start_link, }; static const struct dw_pcie_host_ops kirin_pcie_host_ops = { diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 7ac08f0cae17..8eb8ac2fb270 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -207,18 +207,15 @@ static void qcom_ep_reset_deassert(struct qcom_pcie *pcie) usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500); } -static int qcom_pcie_establish_link(struct qcom_pcie *pcie) +static int qcom_pcie_start_link(struct dw_pcie *pci) { - struct dw_pcie *pci = pcie->pci; - - if (dw_pcie_link_up(pci)) - return 0; + struct qcom_pcie *pcie = to_qcom_pcie(pci); /* Enable Link Training state machine */ if (pcie->ops->ltssm_enable) pcie->ops->ltssm_enable(pcie); - return dw_pcie_wait_for_link(pci); + return 0; } static void qcom_pcie_2_1_0_ltssm_enable(struct qcom_pcie *pcie) @@ -1288,15 +1285,8 @@ static int qcom_pcie_host_init(struct pcie_port *pp) qcom_ep_reset_deassert(pcie); - ret = qcom_pcie_establish_link(pcie); - if (ret) - goto err; - return 0; -err: - qcom_ep_reset_assert(pcie); - if (pcie->ops->post_deinit) - pcie->ops->post_deinit(pcie); + err_disable_phy: phy_power_off(pcie->phy); err_deinit: @@ -1363,6 +1353,7 @@ static const struct qcom_pcie_ops ops_2_7_0 = { static const struct dw_pcie_ops dw_pcie_ops = { .link_up = qcom_pcie_link_up, + .start_link = qcom_pcie_start_link, }; static int qcom_pcie_probe(struct platform_device *pdev) diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c index 800c34a60a33..ebbaa06fc8ab 100644 --- a/drivers/pci/controller/dwc/pcie-spear13xx.c +++ b/drivers/pci/controller/dwc/pcie-spear13xx.c @@ -66,32 +66,10 @@ struct pcie_app_reg { #define to_spear13xx_pcie(x) dev_get_drvdata((x)->dev) -static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie) +static int spear13xx_pcie_start_link(struct dw_pcie *pci) { - struct dw_pcie *pci = spear13xx_pcie->pci; - struct pcie_port *pp = &pci->pp; + struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pci); struct pcie_app_reg *app_reg = spear13xx_pcie->app_base; - u32 val; - u32 exp_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); - - if (dw_pcie_link_up(pci)) { - dev_err(pci->dev, "link already up\n"); - return 0; - } - - dw_pcie_setup_rc(pp); - - /* - * this controller support only 128 bytes read size, however its - * default value in capability register is 512 bytes. So force - * it to 128 here. - */ - val = dw_pcie_readw_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL); - val &= ~PCI_EXP_DEVCTL_READRQ; - dw_pcie_writew_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL, val); - - dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, 0x104A); - dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, 0xCD80); /* enable ltssm */ writel(DEVICE_TYPE_RC | (1 << MISCTRL_EN_ID) @@ -99,7 +77,7 @@ static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie) | ((u32)1 << REG_TRANSLATION_ENABLE), &app_reg->app_ctrl_0); - return dw_pcie_wait_for_link(pci); + return 0; } static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg) @@ -151,10 +129,25 @@ static int spear13xx_pcie_host_init(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pci); + u32 exp_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + u32 val; spear13xx_pcie->app_base = pci->dbi_base + 0x2000; - spear13xx_pcie_establish_link(spear13xx_pcie); + dw_pcie_setup_rc(pp); + + /* + * this controller support only 128 bytes read size, however its + * default value in capability register is 512 bytes. So force + * it to 128 here. + */ + val = dw_pcie_readw_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL); + val &= ~PCI_EXP_DEVCTL_READRQ; + dw_pcie_writew_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL, val); + + dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, 0x104A); + dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, 0xCD80); + spear13xx_pcie_enable_interrupts(spear13xx_pcie); return 0; @@ -198,6 +191,7 @@ static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie, static const struct dw_pcie_ops dw_pcie_ops = { .link_up = spear13xx_pcie_link_up, + .start_link = spear13xx_pcie_start_link, }; static int spear13xx_pcie_probe(struct platform_device *pdev) diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 77fc3ba3dec1..f7d7b002a06d 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1549,7 +1549,6 @@ static int tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie) static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie) { - struct pcie_port *pp = &pcie->pci.pp; struct device *dev = pcie->dev; char *name; int ret; diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c index 6198bd106b8a..f4b776e231d6 100644 --- a/drivers/pci/controller/dwc/pcie-uniphier.c +++ b/drivers/pci/controller/dwc/pcie-uniphier.c @@ -146,16 +146,13 @@ static int uniphier_pcie_link_up(struct dw_pcie *pci) return (val & mask) == mask; } -static int uniphier_pcie_establish_link(struct dw_pcie *pci) +static int uniphier_pcie_start_link(struct dw_pcie *pci) { struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci); - if (dw_pcie_link_up(pci)) - return 0; - uniphier_pcie_ltssm_enable(priv, true); - return dw_pcie_wait_for_link(pci); + return 0; } static void uniphier_pcie_stop_link(struct dw_pcie *pci) @@ -318,10 +315,6 @@ static int uniphier_pcie_host_init(struct pcie_port *pp) uniphier_pcie_irq_enable(priv); dw_pcie_setup_rc(pp); - ret = uniphier_pcie_establish_link(pci); - if (ret) - return ret; - dw_pcie_msi_init(pp); return 0; @@ -385,7 +378,7 @@ out_clk_disable: } static const struct dw_pcie_ops dw_pcie_ops = { - .start_link = uniphier_pcie_establish_link, + .start_link = uniphier_pcie_start_link, .stop_link = uniphier_pcie_stop_link, .link_up = uniphier_pcie_link_up, }; -- cgit v1.2.3 From 59fbab1ae40eb048eb2bd2385a5b981051513458 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 5 Nov 2020 15:11:54 -0600 Subject: PCI: dwc: Move dw_pcie_msi_init() into core The host drivers which call dw_pcie_msi_init() are all the ones using the built-in MSI controller, so let's move it into the common DWC code. Link: https://lore.kernel.org/r/20201105211159.1814485-12-robh@kernel.org Tested-by: Marek Szyprowski Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Acked-by: Jingoo Han Cc: Kishon Vijay Abraham I Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Kukjin Kim Cc: Krzysztof Kozlowski Cc: Richard Zhu Cc: Lucas Stach Cc: Shawn Guo Cc: Sascha Hauer Cc: Pengutronix Kernel Team Cc: Fabio Estevam Cc: NXP Linux Team Cc: Yue Wang Cc: Kevin Hilman Cc: Neil Armstrong Cc: Jerome Brunet Cc: Martin Blumenstingl Cc: Jesper Nilsson Cc: Gustavo Pimentel Cc: Xiaowei Song Cc: Binghui Wang Cc: Stanimir Varbanov Cc: Andy Gross Cc: Bjorn Andersson Cc: Pratyush Anand Cc: Thierry Reding Cc: Jonathan Hunter Cc: Kunihiko Hayashi Cc: Masahiro Yamada Cc: linux-omap@vger.kernel.org Cc: linux-samsung-soc@vger.kernel.org Cc: linux-amlogic@lists.infradead.org Cc: linux-arm-kernel@axis.com Cc: linux-arm-msm@vger.kernel.org Cc: linux-tegra@vger.kernel.org --- drivers/pci/controller/dwc/pci-dra7xx.c | 2 -- drivers/pci/controller/dwc/pci-exynos.c | 4 ---- drivers/pci/controller/dwc/pci-imx6.c | 1 - drivers/pci/controller/dwc/pci-meson.c | 1 - drivers/pci/controller/dwc/pcie-artpec6.c | 1 - drivers/pci/controller/dwc/pcie-designware-host.c | 9 +++++---- drivers/pci/controller/dwc/pcie-designware-plat.c | 1 - drivers/pci/controller/dwc/pcie-designware.h | 10 ---------- drivers/pci/controller/dwc/pcie-histb.c | 2 -- drivers/pci/controller/dwc/pcie-kirin.c | 1 - drivers/pci/controller/dwc/pcie-qcom.c | 2 -- drivers/pci/controller/dwc/pcie-spear13xx.c | 6 +----- drivers/pci/controller/dwc/pcie-tegra194.c | 2 -- drivers/pci/controller/dwc/pcie-uniphier.c | 1 - 14 files changed, 6 insertions(+), 37 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index 054423d9646d..72a5a2bf933b 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -182,8 +182,6 @@ static int dra7xx_pcie_host_init(struct pcie_port *pp) struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); dw_pcie_setup_rc(pp); - - dw_pcie_msi_init(pp); dra7xx_pcie_enable_interrupts(dra7xx); return 0; diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index 6498b615c834..3939fe22e8a2 100644 --- a/drivers/pci/controller/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c @@ -273,12 +273,8 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg) static void exynos_pcie_msi_init(struct exynos_pcie *ep) { - struct dw_pcie *pci = ep->pci; - struct pcie_port *pp = &pci->pp; u32 val; - dw_pcie_msi_init(pp); - /* enable MSI interrupt */ val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_EN_LEVEL); val |= IRQ_MSI_ENABLE; diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 1fe8f3f2c380..9e30fbf4efbe 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -835,7 +835,6 @@ static int imx6_pcie_host_init(struct pcie_port *pp) imx6_pcie_deassert_core_reset(imx6_pcie); imx6_setup_phy_mpll(imx6_pcie); dw_pcie_setup_rc(pp); - dw_pcie_msi_init(pp); return 0; } diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index 41a3351b100b..2df0adcf0bf2 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -381,7 +381,6 @@ static int meson_pcie_host_init(struct pcie_port *pp) meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE); dw_pcie_setup_rc(pp); - dw_pcie_msi_init(pp); return 0; } diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index 8b3da3038ac3..7ee8f3c83f8f 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c @@ -329,7 +329,6 @@ static int artpec6_pcie_host_init(struct pcie_port *pp) artpec6_pcie_deassert_core_reset(artpec6_pcie); artpec6_pcie_wait_for_phy(artpec6_pcie); dw_pcie_setup_rc(pp); - dw_pcie_msi_init(pp); return 0; } diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 800e7a0415cf..ebea2c814448 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -256,7 +256,7 @@ int dw_pcie_allocate_domains(struct pcie_port *pp) return 0; } -void dw_pcie_free_msi(struct pcie_port *pp) +static void dw_pcie_free_msi(struct pcie_port *pp) { if (pp->msi_irq) { irq_set_chained_handler(pp->msi_irq, NULL); @@ -275,19 +275,18 @@ void dw_pcie_free_msi(struct pcie_port *pp) } } -void dw_pcie_msi_init(struct pcie_port *pp) +static void dw_pcie_msi_init(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); u64 msi_target = (u64)pp->msi_data; - if (!IS_ENABLED(CONFIG_PCI_MSI)) + if (!pci_msi_enabled() || !pp->has_msi_ctrl) return; /* Program the msi_data */ dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_LO, lower_32_bits(msi_target)); dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_HI, upper_32_bits(msi_target)); } -EXPORT_SYMBOL_GPL(dw_pcie_msi_init); int dw_pcie_host_init(struct pcie_port *pp) { @@ -423,6 +422,8 @@ int dw_pcie_host_init(struct pcie_port *pp) goto err_free_msi; } + dw_pcie_msi_init(pp); + if (!dw_pcie_link_up(pci) && pci->ops->start_link) { ret = pci->ops->start_link(pci); if (ret) diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index adebcaeb1a6c..dec24e595c3e 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -36,7 +36,6 @@ static const struct of_device_id dw_plat_pcie_of_match[]; static int dw_plat_pcie_host_init(struct pcie_port *pp) { dw_pcie_setup_rc(pp); - dw_pcie_msi_init(pp); return 0; } diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index a6ef286000a6..3447ddccb3c9 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -364,8 +364,6 @@ static inline void dw_pcie_dbi_ro_wr_dis(struct dw_pcie *pci) #ifdef CONFIG_PCIE_DW_HOST irqreturn_t dw_handle_msi_irq(struct pcie_port *pp); -void dw_pcie_msi_init(struct pcie_port *pp); -void dw_pcie_free_msi(struct pcie_port *pp); void dw_pcie_setup_rc(struct pcie_port *pp); int dw_pcie_host_init(struct pcie_port *pp); void dw_pcie_host_deinit(struct pcie_port *pp); @@ -378,14 +376,6 @@ static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) return IRQ_NONE; } -static inline void dw_pcie_msi_init(struct pcie_port *pp) -{ -} - -static inline void dw_pcie_free_msi(struct pcie_port *pp) -{ -} - static inline void dw_pcie_setup_rc(struct pcie_port *pp) { } diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c index ece544165059..210777c793ea 100644 --- a/drivers/pci/controller/dwc/pcie-histb.c +++ b/drivers/pci/controller/dwc/pcie-histb.c @@ -199,8 +199,6 @@ static int histb_pcie_host_init(struct pcie_port *pp) /* setup root complex */ dw_pcie_setup_rc(pp); - dw_pcie_msi_init(pp); - return 0; } diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index 675b4d8392d3..f84ac1b36b2c 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c @@ -406,7 +406,6 @@ static int kirin_pcie_host_init(struct pcie_port *pp) pp->bridge->ops = &kirin_pci_ops; dw_pcie_setup_rc(pp); - dw_pcie_msi_init(pp); return 0; } diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 8eb8ac2fb270..eb107179d544 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1281,8 +1281,6 @@ static int qcom_pcie_host_init(struct pcie_port *pp) } dw_pcie_setup_rc(pp); - dw_pcie_msi_init(pp); - qcom_ep_reset_deassert(pcie); return 0; diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c index ebbaa06fc8ab..31475e4493a7 100644 --- a/drivers/pci/controller/dwc/pcie-spear13xx.c +++ b/drivers/pci/controller/dwc/pcie-spear13xx.c @@ -102,16 +102,12 @@ static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg) static void spear13xx_pcie_enable_interrupts(struct spear13xx_pcie *spear13xx_pcie) { - struct dw_pcie *pci = spear13xx_pcie->pci; - struct pcie_port *pp = &pci->pp; struct pcie_app_reg *app_reg = spear13xx_pcie->app_base; /* Enable MSI interrupt */ - if (IS_ENABLED(CONFIG_PCI_MSI)) { - dw_pcie_msi_init(pp); + if (IS_ENABLED(CONFIG_PCI_MSI)) writel(readl(&app_reg->int_mask) | MSI_CTRL_INT, &app_reg->int_mask); - } } static int spear13xx_pcie_link_up(struct dw_pcie *pci) diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index f7d7b002a06d..84f3e0bb4c7a 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -765,8 +765,6 @@ static void tegra_pcie_enable_msi_interrupts(struct pcie_port *pp) struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); u32 val; - dw_pcie_msi_init(pp); - /* Enable MSI interrupt generation */ val = appl_readl(pcie, APPL_INTR_EN_L0_0); val |= APPL_INTR_EN_L0_0_SYS_MSI_INTR_EN; diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c index f4b776e231d6..e6616408a29c 100644 --- a/drivers/pci/controller/dwc/pcie-uniphier.c +++ b/drivers/pci/controller/dwc/pcie-uniphier.c @@ -315,7 +315,6 @@ static int uniphier_pcie_host_init(struct pcie_port *pp) uniphier_pcie_irq_enable(priv); dw_pcie_setup_rc(pp); - dw_pcie_msi_init(pp); return 0; } -- cgit v1.2.3 From b9ac0f9dc8ea4b91362694e82a1e66313a6c6dc6 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 5 Nov 2020 15:11:55 -0600 Subject: PCI: dwc: Move dw_pcie_setup_rc() to DWC common code All RC complex drivers must call dw_pcie_setup_rc(). The ordering of the call shouldn't be too important other than being after any RC resets. There's a few calls of dw_pcie_setup_rc() left as drivers implementing suspend/resume need it. Link: https://lore.kernel.org/r/20201105211159.1814485-13-robh@kernel.org Tested-by: Marek Szyprowski Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Acked-by: Jingoo Han Cc: Kishon Vijay Abraham I Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Kukjin Kim Cc: Krzysztof Kozlowski Cc: Richard Zhu Cc: Lucas Stach Cc: Shawn Guo Cc: Sascha Hauer Cc: Pengutronix Kernel Team Cc: Fabio Estevam Cc: NXP Linux Team Cc: Murali Karicheri Cc: Minghuan Lian Cc: Mingkai Hu Cc: Roy Zang Cc: Yue Wang Cc: Kevin Hilman Cc: Neil Armstrong Cc: Jerome Brunet Cc: Martin Blumenstingl Cc: Thomas Petazzoni Cc: Jesper Nilsson Cc: Gustavo Pimentel Cc: Xiaowei Song Cc: Binghui Wang Cc: Andy Gross Cc: Bjorn Andersson Cc: Stanimir Varbanov Cc: Pratyush Anand Cc: Kunihiko Hayashi Cc: Masahiro Yamada Cc: linux-omap@vger.kernel.org Cc: linux-samsung-soc@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-amlogic@lists.infradead.org Cc: linux-arm-kernel@axis.com Cc: linux-arm-msm@vger.kernel.org --- drivers/pci/controller/dwc/pci-dra7xx.c | 1 - drivers/pci/controller/dwc/pci-exynos.c | 1 - drivers/pci/controller/dwc/pci-imx6.c | 1 - drivers/pci/controller/dwc/pci-keystone.c | 2 -- drivers/pci/controller/dwc/pci-layerscape.c | 2 -- drivers/pci/controller/dwc/pci-meson.c | 2 -- drivers/pci/controller/dwc/pcie-armada8k.c | 2 -- drivers/pci/controller/dwc/pcie-artpec6.c | 1 - drivers/pci/controller/dwc/pcie-designware-host.c | 1 + drivers/pci/controller/dwc/pcie-designware-plat.c | 8 -------- drivers/pci/controller/dwc/pcie-histb.c | 3 --- drivers/pci/controller/dwc/pcie-kirin.c | 2 -- drivers/pci/controller/dwc/pcie-qcom.c | 1 - drivers/pci/controller/dwc/pcie-spear13xx.c | 2 -- drivers/pci/controller/dwc/pcie-uniphier.c | 2 -- 15 files changed, 1 insertion(+), 30 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index 72a5a2bf933b..b105af63854a 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -181,7 +181,6 @@ static int dra7xx_pcie_host_init(struct pcie_port *pp) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); - dw_pcie_setup_rc(pp); dra7xx_pcie_enable_interrupts(dra7xx); return 0; diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index 3939fe22e8a2..5c10a5432896 100644 --- a/drivers/pci/controller/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c @@ -372,7 +372,6 @@ static int exynos_pcie_host_init(struct pcie_port *pp) phy_init(ep->phy); exynos_pcie_deassert_core_reset(ep); - dw_pcie_setup_rc(pp); exynos_pcie_assert_reset(ep); exynos_pcie_enable_interrupts(ep); diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 9e30fbf4efbe..f9547bb2cf1b 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -834,7 +834,6 @@ static int imx6_pcie_host_init(struct pcie_port *pp) imx6_pcie_init_phy(imx6_pcie); imx6_pcie_deassert_core_reset(imx6_pcie); imx6_setup_phy_mpll(imx6_pcie); - dw_pcie_setup_rc(pp); return 0; } diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 90b222b020a3..5a4bcc2b1ddb 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -807,8 +807,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) if (ret) return ret; - dw_pcie_setup_rc(pp); - ks_pcie_stop_link(pci); ks_pcie_setup_rc_app_regs(ks_pcie); writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8), diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index 0d84986c4c16..400ebbebd00f 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -136,8 +136,6 @@ static int ls_pcie_host_init(struct pcie_port *pp) ls_pcie_drop_msg_tlp(pcie); - dw_pcie_setup_rc(pp); - return 0; } diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index 2df0adcf0bf2..04589f0decb2 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -380,8 +380,6 @@ static int meson_pcie_host_init(struct pcie_port *pp) meson_set_max_payload(mp, MAX_PAYLOAD_SIZE); meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE); - dw_pcie_setup_rc(pp); - return 0; } diff --git a/drivers/pci/controller/dwc/pcie-armada8k.c b/drivers/pci/controller/dwc/pcie-armada8k.c index dd2926bbb901..4e2552dcf982 100644 --- a/drivers/pci/controller/dwc/pcie-armada8k.c +++ b/drivers/pci/controller/dwc/pcie-armada8k.c @@ -171,8 +171,6 @@ static int armada8k_pcie_host_init(struct pcie_port *pp) u32 reg; struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - dw_pcie_setup_rc(pp); - if (!dw_pcie_link_up(pci)) { /* Disable LTSSM state machine to enable configuration */ reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG); diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index 7ee8f3c83f8f..fcba9915a606 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c @@ -328,7 +328,6 @@ static int artpec6_pcie_host_init(struct pcie_port *pp) artpec6_pcie_init_phy(artpec6_pcie); artpec6_pcie_deassert_core_reset(artpec6_pcie); artpec6_pcie_wait_for_phy(artpec6_pcie); - dw_pcie_setup_rc(pp); return 0; } diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index ebea2c814448..f2b0a15ad72b 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -422,6 +422,7 @@ int dw_pcie_host_init(struct pcie_port *pp) goto err_free_msi; } + dw_pcie_setup_rc(pp); dw_pcie_msi_init(pp); if (!dw_pcie_link_up(pci) && pci->ops->start_link) { diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index dec24e595c3e..9b397c807261 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -33,15 +33,7 @@ struct dw_plat_pcie_of_data { static const struct of_device_id dw_plat_pcie_of_match[]; -static int dw_plat_pcie_host_init(struct pcie_port *pp) -{ - dw_pcie_setup_rc(pp); - - return 0; -} - static const struct dw_pcie_host_ops dw_plat_pcie_host_ops = { - .host_init = dw_plat_pcie_host_init, }; static int dw_plat_pcie_establish_link(struct dw_pcie *pci) diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c index 210777c793ea..86f9d16c50d7 100644 --- a/drivers/pci/controller/dwc/pcie-histb.c +++ b/drivers/pci/controller/dwc/pcie-histb.c @@ -196,9 +196,6 @@ static int histb_pcie_host_init(struct pcie_port *pp) regval |= PCIE_WM_RC; histb_pcie_writel(hipcie, PCIE_SYS_CTRL0, regval); - /* setup root complex */ - dw_pcie_setup_rc(pp); - return 0; } diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index f84ac1b36b2c..ac4bbdaf5324 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c @@ -405,8 +405,6 @@ static int kirin_pcie_host_init(struct pcie_port *pp) { pp->bridge->ops = &kirin_pci_ops; - dw_pcie_setup_rc(pp); - return 0; } diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index eb107179d544..e49791c4f846 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1280,7 +1280,6 @@ static int qcom_pcie_host_init(struct pcie_port *pp) goto err_disable_phy; } - dw_pcie_setup_rc(pp); qcom_ep_reset_deassert(pcie); return 0; diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c index 31475e4493a7..1a9e353bef55 100644 --- a/drivers/pci/controller/dwc/pcie-spear13xx.c +++ b/drivers/pci/controller/dwc/pcie-spear13xx.c @@ -130,8 +130,6 @@ static int spear13xx_pcie_host_init(struct pcie_port *pp) spear13xx_pcie->app_base = pci->dbi_base + 0x2000; - dw_pcie_setup_rc(pp); - /* * this controller support only 128 bytes read size, however its * default value in capability register is 512 bytes. So force diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c index e6616408a29c..2457e9dd098d 100644 --- a/drivers/pci/controller/dwc/pcie-uniphier.c +++ b/drivers/pci/controller/dwc/pcie-uniphier.c @@ -314,8 +314,6 @@ static int uniphier_pcie_host_init(struct pcie_port *pp) uniphier_pcie_irq_enable(priv); - dw_pcie_setup_rc(pp); - return 0; } -- cgit v1.2.3 From 60f5b73fa0f298e8f7321deeb634e618b1c3d074 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 5 Nov 2020 15:11:56 -0600 Subject: PCI: dwc: Remove unnecessary wrappers around dw_pcie_host_init() Many calls to dw_pcie_host_init() are in a wrapper function with nothing else now. Let's remove the pointless extra layer. Link: https://lore.kernel.org/r/20201105211159.1814485-14-robh@kernel.org Tested-by: Marek Szyprowski Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Richard Zhu Cc: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Shawn Guo Cc: Sascha Hauer Cc: Pengutronix Kernel Team Cc: Fabio Estevam Cc: NXP Linux Team Cc: Murali Karicheri Cc: Minghuan Lian Cc: Mingkai Hu Cc: Roy Zang Cc: Yue Wang Cc: Kevin Hilman Cc: Neil Armstrong Cc: Jerome Brunet Cc: Martin Blumenstingl Cc: Jonathan Chocron Cc: Jesper Nilsson Cc: Xiaowei Song Cc: Binghui Wang Cc: Kunihiko Hayashi Cc: Masahiro Yamada Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-amlogic@lists.infradead.org Cc: linux-arm-kernel@axis.com --- drivers/pci/controller/dwc/pci-imx6.c | 22 ++-------------------- drivers/pci/controller/dwc/pci-keystone.c | 19 +------------------ drivers/pci/controller/dwc/pci-layerscape.c | 26 ++------------------------ drivers/pci/controller/dwc/pci-meson.c | 22 ++-------------------- drivers/pci/controller/dwc/pcie-al.c | 20 ++------------------ drivers/pci/controller/dwc/pcie-artpec6.c | 23 +++-------------------- drivers/pci/controller/dwc/pcie-kirin.c | 11 ++--------- drivers/pci/controller/dwc/pcie-uniphier.c | 23 +++-------------------- 8 files changed, 17 insertions(+), 149 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index f9547bb2cf1b..0cf1333c0440 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -842,25 +842,6 @@ static const struct dw_pcie_host_ops imx6_pcie_host_ops = { .host_init = imx6_pcie_host_init, }; -static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie, - struct platform_device *pdev) -{ - struct dw_pcie *pci = imx6_pcie->pci; - struct pcie_port *pp = &pci->pp; - struct device *dev = &pdev->dev; - int ret; - - pp->ops = &imx6_pcie_host_ops; - - ret = dw_pcie_host_init(pp); - if (ret) { - dev_err(dev, "failed to initialize host\n"); - return ret; - } - - return 0; -} - static const struct dw_pcie_ops dw_pcie_ops = { .start_link = imx6_pcie_start_link, }; @@ -1005,6 +986,7 @@ static int imx6_pcie_probe(struct platform_device *pdev) pci->dev = dev; pci->ops = &dw_pcie_ops; + pci->pp.ops = &imx6_pcie_host_ops; imx6_pcie->pci = pci; imx6_pcie->drvdata = of_device_get_match_data(dev); @@ -1154,7 +1136,7 @@ static int imx6_pcie_probe(struct platform_device *pdev) if (ret) return ret; - ret = imx6_add_pcie_port(imx6_pcie, pdev); + ret = dw_pcie_host_init(&pci->pp); if (ret < 0) return ret; diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 5a4bcc2b1ddb..719756160821 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -844,23 +844,6 @@ static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv) return ks_pcie_handle_error_irq(ks_pcie); } -static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, - struct platform_device *pdev) -{ - struct dw_pcie *pci = ks_pcie->pci; - struct pcie_port *pp = &pci->pp; - struct device *dev = &pdev->dev; - int ret; - - ret = dw_pcie_host_init(pp); - if (ret) { - dev_err(dev, "failed to initialize host\n"); - return ret; - } - - return 0; -} - static void ks_pcie_am654_write_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg, size_t size, u32 val) { @@ -1255,7 +1238,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) } pci->pp.ops = host_ops; - ret = ks_pcie_add_pcie_port(ks_pcie, pdev); + ret = dw_pcie_host_init(&pci->pp); if (ret < 0) goto err_get_sync; break; diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index 400ebbebd00f..44ad34cdc3bc 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -232,31 +232,12 @@ static const struct of_device_id ls_pcie_of_match[] = { { }, }; -static int __init ls_add_pcie_port(struct ls_pcie *pcie) -{ - struct dw_pcie *pci = pcie->pci; - struct pcie_port *pp = &pci->pp; - struct device *dev = pci->dev; - int ret; - - pp->ops = pcie->drvdata->ops; - - ret = dw_pcie_host_init(pp); - if (ret) { - dev_err(dev, "failed to initialize host\n"); - return ret; - } - - return 0; -} - static int __init ls_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct dw_pcie *pci; struct ls_pcie *pcie; struct resource *dbi_base; - int ret; pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); if (!pcie) @@ -270,6 +251,7 @@ static int __init ls_pcie_probe(struct platform_device *pdev) pci->dev = dev; pci->ops = pcie->drvdata->dw_pcie_ops; + pci->pp.ops = pcie->drvdata->ops; pcie->pci = pci; @@ -285,11 +267,7 @@ static int __init ls_pcie_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pcie); - ret = ls_add_pcie_port(pcie); - if (ret < 0) - return ret; - - return 0; + return dw_pcie_host_init(&pci->pp); } static struct platform_driver ls_pcie_driver = { diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index 04589f0decb2..686ded034f22 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -387,25 +387,6 @@ static const struct dw_pcie_host_ops meson_pcie_host_ops = { .host_init = meson_pcie_host_init, }; -static int meson_add_pcie_port(struct meson_pcie *mp, - struct platform_device *pdev) -{ - struct dw_pcie *pci = &mp->pci; - struct pcie_port *pp = &pci->pp; - struct device *dev = &pdev->dev; - int ret; - - pp->ops = &meson_pcie_host_ops; - - ret = dw_pcie_host_init(pp); - if (ret) { - dev_err(dev, "failed to initialize host\n"); - return ret; - } - - return 0; -} - static const struct dw_pcie_ops dw_pcie_ops = { .link_up = meson_pcie_link_up, .start_link = meson_pcie_start_link, @@ -425,6 +406,7 @@ static int meson_pcie_probe(struct platform_device *pdev) pci = &mp->pci; pci->dev = dev; pci->ops = &dw_pcie_ops; + pci->pp.ops = &meson_pcie_host_ops; pci->num_lanes = 1; mp->phy = devm_phy_get(dev, "pcie"); @@ -471,7 +453,7 @@ static int meson_pcie_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mp); - ret = meson_add_pcie_port(mp, pdev); + ret = dw_pcie_host_init(&pci->pp); if (ret < 0) { dev_err(dev, "Add PCIe port failed, %d\n", ret); goto err_phy; diff --git a/drivers/pci/controller/dwc/pcie-al.c b/drivers/pci/controller/dwc/pcie-al.c index d06866921187..7ac8a37d9ce0 100644 --- a/drivers/pci/controller/dwc/pcie-al.c +++ b/drivers/pci/controller/dwc/pcie-al.c @@ -322,23 +322,6 @@ static const struct dw_pcie_host_ops al_pcie_host_ops = { .host_init = al_pcie_host_init, }; -static int al_add_pcie_port(struct pcie_port *pp, - struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - int ret; - - pp->ops = &al_pcie_host_ops; - - ret = dw_pcie_host_init(pp); - if (ret) { - dev_err(dev, "failed to initialize host\n"); - return ret; - } - - return 0; -} - static const struct dw_pcie_ops dw_pcie_ops = { }; @@ -360,6 +343,7 @@ static int al_pcie_probe(struct platform_device *pdev) pci->dev = dev; pci->ops = &dw_pcie_ops; + pci->pp.ops = &al_pcie_host_ops; al_pcie->pci = pci; al_pcie->dev = dev; @@ -384,7 +368,7 @@ static int al_pcie_probe(struct platform_device *pdev) platform_set_drvdata(pdev, al_pcie); - return al_add_pcie_port(&pci->pp, pdev); + return dw_pcie_host_init(&pci->pp); } static const struct of_device_id al_pcie_of_match[] = { diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index fcba9915a606..597c282f586c 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c @@ -336,25 +336,6 @@ static const struct dw_pcie_host_ops artpec6_pcie_host_ops = { .host_init = artpec6_pcie_host_init, }; -static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie, - struct platform_device *pdev) -{ - struct dw_pcie *pci = artpec6_pcie->pci; - struct pcie_port *pp = &pci->pp; - struct device *dev = pci->dev; - int ret; - - pp->ops = &artpec6_pcie_host_ops; - - ret = dw_pcie_host_init(pp); - if (ret) { - dev_err(dev, "failed to initialize host\n"); - return ret; - } - - return 0; -} - static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); @@ -445,7 +426,9 @@ static int artpec6_pcie_probe(struct platform_device *pdev) if (!IS_ENABLED(CONFIG_PCIE_ARTPEC6_HOST)) return -ENODEV; - ret = artpec6_add_pcie_port(artpec6_pcie, pdev); + pci->pp.ops = &artpec6_pcie_host_ops; + + ret = dw_pcie_host_init(&pci->pp); if (ret < 0) return ret; break; diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index ac4bbdaf5324..026fd1e42a55 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c @@ -419,14 +419,6 @@ static const struct dw_pcie_host_ops kirin_pcie_host_ops = { .host_init = kirin_pcie_host_init, }; -static int kirin_add_pcie_port(struct dw_pcie *pci, - struct platform_device *pdev) -{ - pci->pp.ops = &kirin_pcie_host_ops; - - return dw_pcie_host_init(&pci->pp); -} - static int kirin_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -449,6 +441,7 @@ static int kirin_pcie_probe(struct platform_device *pdev) pci->dev = dev; pci->ops = &kirin_dw_pcie_ops; + pci->pp.ops = &kirin_pcie_host_ops; kirin_pcie->pci = pci; ret = kirin_pcie_get_clk(kirin_pcie, pdev); @@ -474,7 +467,7 @@ static int kirin_pcie_probe(struct platform_device *pdev) platform_set_drvdata(pdev, kirin_pcie); - return kirin_add_pcie_port(pci, pdev); + return dw_pcie_host_init(&pci->pp); } static const struct of_device_id kirin_pcie_match[] = { diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c index 2457e9dd098d..7e8bad326770 100644 --- a/drivers/pci/controller/dwc/pcie-uniphier.c +++ b/drivers/pci/controller/dwc/pcie-uniphier.c @@ -321,25 +321,6 @@ static const struct dw_pcie_host_ops uniphier_pcie_host_ops = { .host_init = uniphier_pcie_host_init, }; -static int uniphier_add_pcie_port(struct uniphier_pcie_priv *priv, - struct platform_device *pdev) -{ - struct dw_pcie *pci = &priv->pci; - struct pcie_port *pp = &pci->pp; - struct device *dev = &pdev->dev; - int ret; - - pp->ops = &uniphier_pcie_host_ops; - - ret = dw_pcie_host_init(pp); - if (ret) { - dev_err(dev, "Failed to initialize host (%d)\n", ret); - return ret; - } - - return 0; -} - static int uniphier_pcie_host_enable(struct uniphier_pcie_priv *priv) { int ret; @@ -415,7 +396,9 @@ static int uniphier_pcie_probe(struct platform_device *pdev) if (ret) return ret; - return uniphier_add_pcie_port(priv, pdev); + priv->pci.pp.ops = &uniphier_pcie_host_ops; + + return dw_pcie_host_init(&priv->pci.pp); } static const struct of_device_id uniphier_pcie_match[] = { -- cgit v1.2.3 From fcde397422ef621e52dac509e253d5e8a8f43b23 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 5 Nov 2020 15:11:57 -0600 Subject: Revert "PCI: dwc/keystone: Drop duplicated 'num-viewport'" This reverts commit 421063efaf1e8f2ac6248cca0064e5877e375f87. In preparation to detect the number of iATU regions instead of using DT properties, we need to keep reading 'num-viewport' for the Keystone driver which doesn't use the iATU in older versions of the IP. However, note that Keystone has been broken for some time with upstream dts files which don't set 'num-viewports'. The reverted commit did make the property optional, but now it's mandatory again. Link: https://lore.kernel.org/r/20201105211159.1814485-15-robh@kernel.org Tested-by: Marek Szyprowski Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Murali Karicheri Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pci-keystone.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 719756160821..53aa35cb3a49 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -121,6 +121,7 @@ struct keystone_pcie { int msi_host_irq; int num_lanes; + u32 num_viewport; struct phy **phy; struct device_link **link; struct device_node *msi_intc_np; @@ -386,9 +387,9 @@ static void ks_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie) static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) { u32 val; + u32 num_viewport = ks_pcie->num_viewport; struct dw_pcie *pci = ks_pcie->pci; struct pcie_port *pp = &pci->pp; - u32 num_viewport = pci->num_viewport; u64 start, end; struct resource *mem; int i; @@ -1093,6 +1094,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) struct resource *res; unsigned int version; void __iomem *base; + u32 num_viewport; struct phy **phy; u32 num_lanes; char name[10]; @@ -1224,6 +1226,12 @@ static int __init ks_pcie_probe(struct platform_device *pdev) goto err_get_sync; } + ret = of_property_read_u32(np, "num-viewport", &num_viewport); + if (ret < 0) { + dev_err(dev, "unable to read *num-viewport* property\n"); + goto err_get_sync; + } + /* * "Power Sequencing and Reset Signal Timings" table in * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 2.0 @@ -1237,6 +1245,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) gpiod_set_value_cansleep(gpiod, 1); } + ks_pcie->num_viewport = num_viewport; pci->pp.ops = host_ops; ret = dw_pcie_host_init(&pci->pp); if (ret < 0) -- cgit v1.2.3 From 9ca17af552bcd28cb91b6317edd945b4134411fa Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 5 Nov 2020 15:11:58 -0600 Subject: PCI: dwc: Move inbound and outbound windows to common struct The number of inbound and outbound windows are defined by the h/w and apply to both RC and EP modes, so move them to the appropriate struct. Link: https://lore.kernel.org/r/20201105211159.1814485-16-robh@kernel.org Tested-by: Marek Szyprowski Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Jingoo Han Cc: Gustavo Pimentel Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-designware-ep.c | 25 +++++++++++++------------ drivers/pci/controller/dwc/pcie-designware.h | 4 ++-- 2 files changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 6fe176e1bdd2..79b998982e41 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -161,8 +161,8 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, u32 free_win; struct dw_pcie *pci = to_dw_pcie_from_ep(ep); - free_win = find_first_zero_bit(ep->ib_window_map, ep->num_ib_windows); - if (free_win >= ep->num_ib_windows) { + free_win = find_first_zero_bit(ep->ib_window_map, pci->num_ib_windows); + if (free_win >= pci->num_ib_windows) { dev_err(pci->dev, "No free inbound window\n"); return -EINVAL; } @@ -187,8 +187,8 @@ static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, u8 func_no, u32 free_win; struct dw_pcie *pci = to_dw_pcie_from_ep(ep); - free_win = find_first_zero_bit(ep->ob_window_map, ep->num_ob_windows); - if (free_win >= ep->num_ob_windows) { + free_win = find_first_zero_bit(ep->ob_window_map, pci->num_ob_windows); + if (free_win >= pci->num_ob_windows) { dev_err(pci->dev, "No free outbound window\n"); return -EINVAL; } @@ -264,8 +264,9 @@ static int dw_pcie_find_index(struct dw_pcie_ep *ep, phys_addr_t addr, u32 *atu_index) { u32 index; + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); - for (index = 0; index < ep->num_ob_windows; index++) { + for (index = 0; index < pci->num_ob_windows; index++) { if (ep->outbound_addr[index] != addr) continue; *atu_index = index; @@ -713,41 +714,41 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) ep->phys_base = res->start; ep->addr_size = resource_size(res); - ret = of_property_read_u32(np, "num-ib-windows", &ep->num_ib_windows); + ret = of_property_read_u32(np, "num-ib-windows", &pci->num_ib_windows); if (ret < 0) { dev_err(dev, "Unable to read *num-ib-windows* property\n"); return ret; } - if (ep->num_ib_windows > MAX_IATU_IN) { + if (pci->num_ib_windows > MAX_IATU_IN) { dev_err(dev, "Invalid *num-ib-windows*\n"); return -EINVAL; } - ret = of_property_read_u32(np, "num-ob-windows", &ep->num_ob_windows); + ret = of_property_read_u32(np, "num-ob-windows", &pci->num_ob_windows); if (ret < 0) { dev_err(dev, "Unable to read *num-ob-windows* property\n"); return ret; } - if (ep->num_ob_windows > MAX_IATU_OUT) { + if (pci->num_ob_windows > MAX_IATU_OUT) { dev_err(dev, "Invalid *num-ob-windows*\n"); return -EINVAL; } ep->ib_window_map = devm_kcalloc(dev, - BITS_TO_LONGS(ep->num_ib_windows), + BITS_TO_LONGS(pci->num_ib_windows), sizeof(long), GFP_KERNEL); if (!ep->ib_window_map) return -ENOMEM; ep->ob_window_map = devm_kcalloc(dev, - BITS_TO_LONGS(ep->num_ob_windows), + BITS_TO_LONGS(pci->num_ob_windows), sizeof(long), GFP_KERNEL); if (!ep->ob_window_map) return -ENOMEM; - addr = devm_kcalloc(dev, ep->num_ob_windows, sizeof(phys_addr_t), + addr = devm_kcalloc(dev, pci->num_ob_windows, sizeof(phys_addr_t), GFP_KERNEL); if (!addr) return -ENOMEM; diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 3447ddccb3c9..ed90eaf36f0f 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -237,8 +237,6 @@ struct dw_pcie_ep { phys_addr_t *outbound_addr; unsigned long *ib_window_map; unsigned long *ob_window_map; - u32 num_ib_windows; - u32 num_ob_windows; void __iomem *msi_mem; phys_addr_t msi_mem_phys; struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS]; @@ -264,6 +262,8 @@ struct dw_pcie { /* Used when iatu_unroll_enabled is true */ void __iomem *atu_base; u32 num_viewport; + u32 num_ib_windows; + u32 num_ob_windows; struct pcie_port pp; struct dw_pcie_ep ep; const struct dw_pcie_ops *ops; -- cgit v1.2.3 From 281f1f99cf3a761b45f611943721dfb1895c68a3 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 5 Nov 2020 15:11:59 -0600 Subject: PCI: dwc: Detect number of iATU windows Currently the number of inbound and outbound iATU windows are determined from DT properties. Unfortunately, there's 'num-viewport' for RC mode and 'num-ib-windows' and 'num-ob-windows' for EP mode, yet the number of windows is not mode dependent. Also, 'num-viewport' is not clear whether that's inbound, outbound or both. We can probably assume it's outbound windows as that's all RC mode uses. However, using DT properties isn't really needed as the number of regions can be detected at runtime by poking the iATU registers. The basic algorithm is just writing a target address and reading back what we wrote. In the unrolled ATU case, we have to take care not to go past the mapped region. With this, we can drop num_viewport in favor of num_ob_windows instead. Link: https://lore.kernel.org/r/20201105211159.1814485-17-robh@kernel.org Tested-by: Marek Szyprowski Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Jingoo Han Cc: Gustavo Pimentel Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Thierry Reding Cc: Jonathan Hunter Cc: linux-tegra@vger.kernel.org --- drivers/pci/controller/dwc/pcie-designware-ep.c | 20 ----- drivers/pci/controller/dwc/pcie-designware-host.c | 14 ++-- drivers/pci/controller/dwc/pcie-designware.c | 93 +++++++++++++++++++++-- drivers/pci/controller/dwc/pcie-designware.h | 2 +- drivers/pci/controller/dwc/pcie-intel-gw.c | 8 -- drivers/pci/controller/dwc/pcie-tegra194.c | 1 + 6 files changed, 93 insertions(+), 45 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 79b998982e41..bcd1cd9ba8c8 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -714,26 +714,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) ep->phys_base = res->start; ep->addr_size = resource_size(res); - ret = of_property_read_u32(np, "num-ib-windows", &pci->num_ib_windows); - if (ret < 0) { - dev_err(dev, "Unable to read *num-ib-windows* property\n"); - return ret; - } - if (pci->num_ib_windows > MAX_IATU_IN) { - dev_err(dev, "Invalid *num-ib-windows*\n"); - return -EINVAL; - } - - ret = of_property_read_u32(np, "num-ob-windows", &pci->num_ob_windows); - if (ret < 0) { - dev_err(dev, "Unable to read *num-ob-windows* property\n"); - return ret; - } - if (pci->num_ob_windows > MAX_IATU_OUT) { - dev_err(dev, "Invalid *num-ob-windows*\n"); - return -EINVAL; - } - ep->ib_window_map = devm_kcalloc(dev, BITS_TO_LONGS(pci->num_ib_windows), sizeof(long), diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index f2b0a15ad72b..99ef808a40a9 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -356,10 +356,6 @@ int dw_pcie_host_init(struct pcie_port *pp) } } - ret = of_property_read_u32(np, "num-viewport", &pci->num_viewport); - if (ret) - pci->num_viewport = 2; - if (pci->link_gen < 1) pci->link_gen = of_pci_get_max_link_speed(np); @@ -598,7 +594,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp) dw_pcie_writel_dbi(pci, PCI_COMMAND, val); /* Ensure all outbound windows are disabled so there are multiple matches */ - for (i = 0; i < pci->num_viewport; i++) + for (i = 0; i < pci->num_ob_windows; i++) dw_pcie_disable_atu(pci, i, DW_PCIE_REGION_OUTBOUND); /* @@ -615,7 +611,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp) if (resource_type(entry->res) != IORESOURCE_MEM) continue; - if (pci->num_viewport <= ++atu_idx) + if (pci->num_ob_windows <= ++atu_idx) break; dw_pcie_prog_outbound_atu(pci, atu_idx, @@ -625,7 +621,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp) } if (pp->io_size) { - if (pci->num_viewport > ++atu_idx) + if (pci->num_ob_windows > ++atu_idx) dw_pcie_prog_outbound_atu(pci, atu_idx, PCIE_ATU_TYPE_IO, pp->io_base, pp->io_bus_addr, pp->io_size); @@ -633,9 +629,9 @@ void dw_pcie_setup_rc(struct pcie_port *pp) pci->io_cfg_atu_shared = true; } - if (pci->num_viewport <= atu_idx) + if (pci->num_ob_windows <= atu_idx) dev_warn(pci->dev, "Resources exceed number of ATU entries (%d)", - pci->num_viewport); + pci->num_ob_windows); } dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0); diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index b5e438b70cd5..645fa1892375 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -546,6 +546,70 @@ static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci) return 0; } +static void dw_pcie_iatu_detect_regions_unroll(struct dw_pcie *pci) +{ + int max_region, i, ob = 0, ib = 0; + u32 val; + + max_region = min((int)pci->atu_size / 512, 256); + + for (i = 0; i < max_region; i++) { + dw_pcie_writel_ob_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET, + 0x11110000); + + val = dw_pcie_readl_ob_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET); + if (val == 0x11110000) + ob++; + else + break; + } + + for (i = 0; i < max_region; i++) { + dw_pcie_writel_ib_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET, + 0x11110000); + + val = dw_pcie_readl_ib_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET); + if (val == 0x11110000) + ib++; + else + break; + } + pci->num_ib_windows = ib; + pci->num_ob_windows = ob; +} + +static void dw_pcie_iatu_detect_regions(struct dw_pcie *pci) +{ + int max_region, i, ob = 0, ib = 0; + u32 val; + + dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, 0xFF); + max_region = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT) + 1; + + for (i = 0; i < max_region; i++) { + dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_OUTBOUND | i); + dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, 0x11110000); + val = dw_pcie_readl_dbi(pci, PCIE_ATU_LOWER_TARGET); + if (val == 0x11110000) + ob++; + else + break; + } + + for (i = 0; i < max_region; i++) { + dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND | i); + dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, 0x11110000); + val = dw_pcie_readl_dbi(pci, PCIE_ATU_LOWER_TARGET); + if (val == 0x11110000) + ib++; + else + break; + } + + pci->num_ib_windows = ib; + pci->num_ob_windows = ob; +} + void dw_pcie_setup(struct dw_pcie *pci) { u32 val; @@ -556,15 +620,30 @@ void dw_pcie_setup(struct dw_pcie *pci) if (pci->version >= 0x480A || (!pci->version && dw_pcie_iatu_unroll_enabled(pci))) { pci->iatu_unroll_enabled = true; - if (!pci->atu_base) - pci->atu_base = - devm_platform_ioremap_resource_byname(pdev, "atu"); - if (IS_ERR(pci->atu_base)) - pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; - } - dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ? + if (!pci->atu_base) { + struct resource *res = + platform_get_resource_byname(pdev, IORESOURCE_MEM, "atu"); + if (res) + pci->atu_size = resource_size(res); + pci->atu_base = devm_ioremap_resource(dev, res); + if (IS_ERR(pci->atu_base)) + pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; + } + + if (!pci->atu_size) + /* Pick a minimal default, enough for 8 in and 8 out windows */ + pci->atu_size = SZ_4K; + + dw_pcie_iatu_detect_regions_unroll(pci); + } else + dw_pcie_iatu_detect_regions(pci); + + dev_info(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ? "enabled" : "disabled"); + dev_info(pci->dev, "Detected iATU regions: %u outbound, %u inbound", + pci->num_ob_windows, pci->num_ib_windows); + if (pci->link_gen > 0) dw_pcie_link_set_max_speed(pci, pci->link_gen); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index ed90eaf36f0f..0207840756c4 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -261,7 +261,7 @@ struct dw_pcie { void __iomem *dbi_base2; /* Used when iatu_unroll_enabled is true */ void __iomem *atu_base; - u32 num_viewport; + size_t atu_size; u32 num_ib_windows; u32 num_ob_windows; struct pcie_port pp; diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c index 292b9de86532..0cedd1f95f37 100644 --- a/drivers/pci/controller/dwc/pcie-intel-gw.c +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c @@ -58,7 +58,6 @@ struct intel_pcie_soc { unsigned int pcie_ver; - u32 num_viewport; }; struct intel_pcie_port { @@ -400,7 +399,6 @@ static const struct dw_pcie_host_ops intel_pcie_dw_ops = { static const struct intel_pcie_soc pcie_data = { .pcie_ver = 0x520A, - .num_viewport = 3, }; static int intel_pcie_probe(struct platform_device *pdev) @@ -443,12 +441,6 @@ static int intel_pcie_probe(struct platform_device *pdev) return ret; } - /* - * Intel PCIe doesn't configure IO region, so set viewport - * to not perform IO region access. - */ - pci->num_viewport = data->num_viewport; - return 0; } diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 84f3e0bb4c7a..fa54d9aaa430 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -2075,6 +2075,7 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev) } pcie->atu_dma_res = atu_dma_res; + pci->atu_size = resource_size(atu_dma_res); pci->atu_base = devm_ioremap_resource(dev, atu_dma_res); if (IS_ERR(pci->atu_base)) return PTR_ERR(pci->atu_base); -- cgit v1.2.3 From 778f7c194b1dac351d345ce723f8747026092949 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Fri, 13 Nov 2020 18:01:39 +0100 Subject: PCI: dwc: exynos: Rework the driver to support Exynos5433 variant Exynos5440 SoC support has been dropped since commit 8c83315da1cf ("ARM: dts: exynos: Remove Exynos5440"). Rework this driver to support DWC PCIe variant found in the Exynos5433 SoCs. The main difference in Exynos5433 variant is lack of the MSI support (the MSI interrupt is not even routed to the CPU). [mszyprow: reworked the driver to support only Exynos5433 variant, simplified code, rebased onto current kernel code, added regulator support, converted to the regular platform driver, removed MSI related code, rewrote commit message, added help] Link: https://lore.kernel.org/r/20201113170139.29956-6-m.szyprowski@samsung.com Signed-off-by: Jaehoon Chung Signed-off-by: Marek Szyprowski Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Acked-by: Krzysztof Kozlowski Acked-by: Jingoo Han --- drivers/pci/controller/dwc/Kconfig | 9 +- drivers/pci/controller/dwc/pci-exynos.c | 353 +++++++++++++------------------- drivers/pci/quirks.c | 1 + 3 files changed, 147 insertions(+), 216 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index bc049865f8e0..9ee1e248e744 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -83,10 +83,15 @@ config PCIE_DW_PLAT_EP selected. config PCI_EXYNOS - bool "Samsung Exynos PCIe controller" - depends on SOC_EXYNOS5440 || COMPILE_TEST + tristate "Samsung Exynos PCIe controller" + depends on ARCH_EXYNOS || COMPILE_TEST depends on PCI_MSI_IRQ_DOMAIN select PCIE_DW_HOST + help + Enables support for the PCIe controller in the Samsung Exynos SoCs + to work in host mode. The PCI controller is based on the DesignWare + hardware and therefore the driver re-uses the DesignWare core + functions to implement the driver. config PCI_IMX6 bool "Freescale i.MX6/7/8 PCIe controller" diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index 5c10a5432896..c24dab383654 100644 --- a/drivers/pci/controller/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c @@ -2,26 +2,23 @@ /* * PCIe host controller driver for Samsung Exynos SoCs * - * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * Copyright (C) 2013-2020 Samsung Electronics Co., Ltd. * https://www.samsung.com * * Author: Jingoo Han + * Jaehoon Chung */ #include #include -#include #include #include #include #include -#include #include #include #include -#include -#include -#include +#include #include "pcie-designware.h" @@ -37,102 +34,43 @@ #define PCIE_IRQ_SPECIAL 0x008 #define PCIE_IRQ_EN_PULSE 0x00c #define PCIE_IRQ_EN_LEVEL 0x010 -#define IRQ_MSI_ENABLE BIT(2) #define PCIE_IRQ_EN_SPECIAL 0x014 -#define PCIE_PWR_RESET 0x018 +#define PCIE_SW_WAKE 0x018 +#define PCIE_BUS_EN BIT(1) #define PCIE_CORE_RESET 0x01c #define PCIE_CORE_RESET_ENABLE BIT(0) #define PCIE_STICKY_RESET 0x020 #define PCIE_NONSTICKY_RESET 0x024 #define PCIE_APP_INIT_RESET 0x028 #define PCIE_APP_LTSSM_ENABLE 0x02c -#define PCIE_ELBI_RDLH_LINKUP 0x064 +#define PCIE_ELBI_RDLH_LINKUP 0x074 +#define PCIE_ELBI_XMLH_LINKUP BIT(4) #define PCIE_ELBI_LTSSM_ENABLE 0x1 #define PCIE_ELBI_SLV_AWMISC 0x11c #define PCIE_ELBI_SLV_ARMISC 0x120 #define PCIE_ELBI_SLV_DBI_ENABLE BIT(21) -struct exynos_pcie_mem_res { - void __iomem *elbi_base; /* DT 0th resource: PCIe CTRL */ -}; - -struct exynos_pcie_clk_res { - struct clk *clk; - struct clk *bus_clk; -}; - struct exynos_pcie { - struct dw_pcie *pci; - struct exynos_pcie_mem_res *mem_res; - struct exynos_pcie_clk_res *clk_res; - const struct exynos_pcie_ops *ops; - int reset_gpio; - + struct dw_pcie pci; + void __iomem *elbi_base; + struct clk *clk; + struct clk *bus_clk; struct phy *phy; + struct regulator_bulk_data supplies[2]; }; -struct exynos_pcie_ops { - int (*get_mem_resources)(struct platform_device *pdev, - struct exynos_pcie *ep); - int (*get_clk_resources)(struct exynos_pcie *ep); - int (*init_clk_resources)(struct exynos_pcie *ep); - void (*deinit_clk_resources)(struct exynos_pcie *ep); -}; - -static int exynos5440_pcie_get_mem_resources(struct platform_device *pdev, - struct exynos_pcie *ep) -{ - struct dw_pcie *pci = ep->pci; - struct device *dev = pci->dev; - - ep->mem_res = devm_kzalloc(dev, sizeof(*ep->mem_res), GFP_KERNEL); - if (!ep->mem_res) - return -ENOMEM; - - ep->mem_res->elbi_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(ep->mem_res->elbi_base)) - return PTR_ERR(ep->mem_res->elbi_base); - - return 0; -} - -static int exynos5440_pcie_get_clk_resources(struct exynos_pcie *ep) +static int exynos_pcie_init_clk_resources(struct exynos_pcie *ep) { - struct dw_pcie *pci = ep->pci; - struct device *dev = pci->dev; - - ep->clk_res = devm_kzalloc(dev, sizeof(*ep->clk_res), GFP_KERNEL); - if (!ep->clk_res) - return -ENOMEM; - - ep->clk_res->clk = devm_clk_get(dev, "pcie"); - if (IS_ERR(ep->clk_res->clk)) { - dev_err(dev, "Failed to get pcie rc clock\n"); - return PTR_ERR(ep->clk_res->clk); - } - - ep->clk_res->bus_clk = devm_clk_get(dev, "pcie_bus"); - if (IS_ERR(ep->clk_res->bus_clk)) { - dev_err(dev, "Failed to get pcie bus clock\n"); - return PTR_ERR(ep->clk_res->bus_clk); - } - - return 0; -} - -static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep) -{ - struct dw_pcie *pci = ep->pci; - struct device *dev = pci->dev; + struct device *dev = ep->pci.dev; int ret; - ret = clk_prepare_enable(ep->clk_res->clk); + ret = clk_prepare_enable(ep->clk); if (ret) { dev_err(dev, "cannot enable pcie rc clock"); return ret; } - ret = clk_prepare_enable(ep->clk_res->bus_clk); + ret = clk_prepare_enable(ep->bus_clk); if (ret) { dev_err(dev, "cannot enable pcie bus clock"); goto err_bus_clk; @@ -141,24 +79,17 @@ static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep) return 0; err_bus_clk: - clk_disable_unprepare(ep->clk_res->clk); + clk_disable_unprepare(ep->clk); return ret; } -static void exynos5440_pcie_deinit_clk_resources(struct exynos_pcie *ep) +static void exynos_pcie_deinit_clk_resources(struct exynos_pcie *ep) { - clk_disable_unprepare(ep->clk_res->bus_clk); - clk_disable_unprepare(ep->clk_res->clk); + clk_disable_unprepare(ep->bus_clk); + clk_disable_unprepare(ep->clk); } -static const struct exynos_pcie_ops exynos5440_pcie_ops = { - .get_mem_resources = exynos5440_pcie_get_mem_resources, - .get_clk_resources = exynos5440_pcie_get_clk_resources, - .init_clk_resources = exynos5440_pcie_init_clk_resources, - .deinit_clk_resources = exynos5440_pcie_deinit_clk_resources, -}; - static void exynos_pcie_writel(void __iomem *base, u32 val, u32 reg) { writel(val, base + reg); @@ -173,94 +104,71 @@ static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *ep, bool on) { u32 val; - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_AWMISC); + val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_AWMISC); if (on) val |= PCIE_ELBI_SLV_DBI_ENABLE; else val &= ~PCIE_ELBI_SLV_DBI_ENABLE; - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_AWMISC); + exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_AWMISC); } static void exynos_pcie_sideband_dbi_r_mode(struct exynos_pcie *ep, bool on) { u32 val; - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_ARMISC); + val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_ARMISC); if (on) val |= PCIE_ELBI_SLV_DBI_ENABLE; else val &= ~PCIE_ELBI_SLV_DBI_ENABLE; - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_ARMISC); + exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_ARMISC); } static void exynos_pcie_assert_core_reset(struct exynos_pcie *ep) { u32 val; - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET); + val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET); val &= ~PCIE_CORE_RESET_ENABLE; - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET); - exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_PWR_RESET); - exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_STICKY_RESET); - exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_NONSTICKY_RESET); + exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET); + exynos_pcie_writel(ep->elbi_base, 0, PCIE_STICKY_RESET); + exynos_pcie_writel(ep->elbi_base, 0, PCIE_NONSTICKY_RESET); } static void exynos_pcie_deassert_core_reset(struct exynos_pcie *ep) { u32 val; - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET); + val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET); val |= PCIE_CORE_RESET_ENABLE; - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET); - exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_STICKY_RESET); - exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_NONSTICKY_RESET); - exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_APP_INIT_RESET); - exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_APP_INIT_RESET); -} - -static void exynos_pcie_assert_reset(struct exynos_pcie *ep) -{ - struct dw_pcie *pci = ep->pci; - struct device *dev = pci->dev; - - if (ep->reset_gpio >= 0) - devm_gpio_request_one(dev, ep->reset_gpio, - GPIOF_OUT_INIT_HIGH, "RESET"); + exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET); + exynos_pcie_writel(ep->elbi_base, 1, PCIE_STICKY_RESET); + exynos_pcie_writel(ep->elbi_base, 1, PCIE_NONSTICKY_RESET); + exynos_pcie_writel(ep->elbi_base, 1, PCIE_APP_INIT_RESET); + exynos_pcie_writel(ep->elbi_base, 0, PCIE_APP_INIT_RESET); } static int exynos_pcie_start_link(struct dw_pcie *pci) { struct exynos_pcie *ep = to_exynos_pcie(pci); + u32 val; + + val = exynos_pcie_readl(ep->elbi_base, PCIE_SW_WAKE); + val &= ~PCIE_BUS_EN; + exynos_pcie_writel(ep->elbi_base, val, PCIE_SW_WAKE); /* assert LTSSM enable */ - exynos_pcie_writel(ep->mem_res->elbi_base, PCIE_ELBI_LTSSM_ENABLE, + exynos_pcie_writel(ep->elbi_base, PCIE_ELBI_LTSSM_ENABLE, PCIE_APP_LTSSM_ENABLE); - - /* check if the link is up or not */ - if (!dw_pcie_wait_for_link(pci)) - return 0; - - phy_power_off(ep->phy); - return -ETIMEDOUT; + return 0; } static void exynos_pcie_clear_irq_pulse(struct exynos_pcie *ep) { - u32 val; - - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_PULSE); - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_PULSE); -} - -static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep) -{ - u32 val; + u32 val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_PULSE); - /* enable INTX interrupt */ - val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT | - IRQ_INTC_ASSERT | IRQ_INTD_ASSERT; - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_PULSE); + exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_PULSE); } static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg) @@ -271,22 +179,14 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg) return IRQ_HANDLED; } -static void exynos_pcie_msi_init(struct exynos_pcie *ep) -{ - u32 val; - - /* enable MSI interrupt */ - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_EN_LEVEL); - val |= IRQ_MSI_ENABLE; - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_LEVEL); -} - -static void exynos_pcie_enable_interrupts(struct exynos_pcie *ep) +static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep) { - exynos_pcie_enable_irq_pulse(ep); + u32 val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT | + IRQ_INTC_ASSERT | IRQ_INTD_ASSERT; - if (IS_ENABLED(CONFIG_PCI_MSI)) - exynos_pcie_msi_init(ep); + exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_EN_PULSE); + exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_LEVEL); + exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_SPECIAL); } static u32 exynos_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, @@ -345,13 +245,9 @@ static struct pci_ops exynos_pci_ops = { static int exynos_pcie_link_up(struct dw_pcie *pci) { struct exynos_pcie *ep = to_exynos_pcie(pci); - u32 val; + u32 val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_RDLH_LINKUP); - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_RDLH_LINKUP); - if (val == PCIE_ELBI_LTSSM_ENABLE) - return 1; - - return 0; + return (val & PCIE_ELBI_XMLH_LINKUP); } static int exynos_pcie_host_init(struct pcie_port *pp) @@ -364,17 +260,11 @@ static int exynos_pcie_host_init(struct pcie_port *pp) exynos_pcie_assert_core_reset(ep); phy_reset(ep->phy); - - exynos_pcie_writel(ep->mem_res->elbi_base, 1, - PCIE_PWR_RESET); - phy_power_on(ep->phy); phy_init(ep->phy); exynos_pcie_deassert_core_reset(ep); - exynos_pcie_assert_reset(ep); - - exynos_pcie_enable_interrupts(ep); + exynos_pcie_enable_irq_pulse(ep); return 0; } @@ -383,26 +273,27 @@ static const struct dw_pcie_host_ops exynos_pcie_host_ops = { .host_init = exynos_pcie_host_init, }; -static int __init exynos_add_pcie_port(struct exynos_pcie *ep, +static int exynos_add_pcie_port(struct exynos_pcie *ep, struct platform_device *pdev) { - struct dw_pcie *pci = ep->pci; + struct dw_pcie *pci = &ep->pci; struct pcie_port *pp = &pci->pp; struct device *dev = &pdev->dev; int ret; - pp->irq = platform_get_irq(pdev, 1); + pp->irq = platform_get_irq(pdev, 0); if (pp->irq < 0) return pp->irq; ret = devm_request_irq(dev, pp->irq, exynos_pcie_irq_handler, - IRQF_SHARED, "exynos-pcie", ep); + IRQF_SHARED, "exynos-pcie", ep); if (ret) { dev_err(dev, "failed to request irq\n"); return ret; } pp->ops = &exynos_pcie_host_ops; + pp->msi_irq = -ENODEV; ret = dw_pcie_host_init(pp); if (ret) { @@ -420,10 +311,9 @@ static const struct dw_pcie_ops dw_pcie_ops = { .start_link = exynos_pcie_start_link, }; -static int __init exynos_pcie_probe(struct platform_device *pdev) +static int exynos_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct dw_pcie *pci; struct exynos_pcie *ep; struct device_node *np = dev->of_node; int ret; @@ -432,43 +322,45 @@ static int __init exynos_pcie_probe(struct platform_device *pdev) if (!ep) return -ENOMEM; - pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); - if (!pci) - return -ENOMEM; - - pci->dev = dev; - pci->ops = &dw_pcie_ops; - - ep->pci = pci; - ep->ops = (const struct exynos_pcie_ops *) - of_device_get_match_data(dev); - - ep->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); + ep->pci.dev = dev; + ep->pci.ops = &dw_pcie_ops; ep->phy = devm_of_phy_get(dev, np, NULL); - if (IS_ERR(ep->phy)) { - if (PTR_ERR(ep->phy) != -ENODEV) - return PTR_ERR(ep->phy); + if (IS_ERR(ep->phy)) + return PTR_ERR(ep->phy); - ep->phy = NULL; - } + /* External Local Bus interface (ELBI) registers */ + ep->elbi_base = devm_platform_ioremap_resource_byname(pdev, "elbi"); + if (IS_ERR(ep->elbi_base)) + return PTR_ERR(ep->elbi_base); - if (ep->ops && ep->ops->get_mem_resources) { - ret = ep->ops->get_mem_resources(pdev, ep); - if (ret) - return ret; + ep->clk = devm_clk_get(dev, "pcie"); + if (IS_ERR(ep->clk)) { + dev_err(dev, "Failed to get pcie rc clock\n"); + return PTR_ERR(ep->clk); } - if (ep->ops && ep->ops->get_clk_resources && - ep->ops->init_clk_resources) { - ret = ep->ops->get_clk_resources(ep); - if (ret) - return ret; - ret = ep->ops->init_clk_resources(ep); - if (ret) - return ret; + ep->bus_clk = devm_clk_get(dev, "pcie_bus"); + if (IS_ERR(ep->bus_clk)) { + dev_err(dev, "Failed to get pcie bus clock\n"); + return PTR_ERR(ep->bus_clk); } + ep->supplies[0].supply = "vdd18"; + ep->supplies[1].supply = "vdd10"; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ep->supplies), + ep->supplies); + if (ret) + return ret; + + ret = exynos_pcie_init_clk_resources(ep); + if (ret) + return ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies); + if (ret) + return ret; + platform_set_drvdata(pdev, ep); ret = exynos_add_pcie_port(ep, pdev); @@ -479,9 +371,9 @@ static int __init exynos_pcie_probe(struct platform_device *pdev) fail_probe: phy_exit(ep->phy); + exynos_pcie_deinit_clk_resources(ep); + regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies); - if (ep->ops && ep->ops->deinit_clk_resources) - ep->ops->deinit_clk_resources(ep); return ret; } @@ -489,32 +381,65 @@ static int __exit exynos_pcie_remove(struct platform_device *pdev) { struct exynos_pcie *ep = platform_get_drvdata(pdev); - if (ep->ops && ep->ops->deinit_clk_resources) - ep->ops->deinit_clk_resources(ep); + dw_pcie_host_deinit(&ep->pci.pp); + exynos_pcie_assert_core_reset(ep); + phy_power_off(ep->phy); + phy_exit(ep->phy); + exynos_pcie_deinit_clk_resources(ep); + regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies); + + return 0; +} + +static int __maybe_unused exynos_pcie_suspend_noirq(struct device *dev) +{ + struct exynos_pcie *ep = dev_get_drvdata(dev); + + exynos_pcie_assert_core_reset(ep); + phy_power_off(ep->phy); + phy_exit(ep->phy); + regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies); return 0; } +static int __maybe_unused exynos_pcie_resume_noirq(struct device *dev) +{ + struct exynos_pcie *ep = dev_get_drvdata(dev); + struct dw_pcie *pci = &ep->pci; + struct pcie_port *pp = &pci->pp; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies); + if (ret) + return ret; + + /* exynos_pcie_host_init controls ep->phy */ + exynos_pcie_host_init(pp); + dw_pcie_setup_rc(pp); + exynos_pcie_start_link(pci); + return dw_pcie_wait_for_link(pci); +} + +static const struct dev_pm_ops exynos_pcie_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos_pcie_suspend_noirq, + exynos_pcie_resume_noirq) +}; + static const struct of_device_id exynos_pcie_of_match[] = { - { - .compatible = "samsung,exynos5440-pcie", - .data = &exynos5440_pcie_ops - }, - {}, + { .compatible = "samsung,exynos5433-pcie", }, + { }, }; static struct platform_driver exynos_pcie_driver = { + .probe = exynos_pcie_probe, .remove = __exit_p(exynos_pcie_remove), .driver = { .name = "exynos-pcie", .of_match_table = exynos_pcie_of_match, + .pm = &exynos_pcie_pm_ops, }, }; - -/* Exynos PCIe driver does not allow module unload */ - -static int __init exynos_pcie_init(void) -{ - return platform_driver_probe(&exynos_pcie_driver, exynos_pcie_probe); -} -subsys_initcall(exynos_pcie_init); +module_platform_driver(exynos_pcie_driver); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, exynos_pcie_of_match); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index f70692ac79c5..8b93f0bba1f2 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2522,6 +2522,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disab DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3364, quirk_disable_all_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8380_0, quirk_disable_all_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, 0x0761, quirk_disable_all_msi); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SAMSUNG, 0xa5e3, quirk_disable_all_msi); /* Disable MSI on chipsets that are known to not support it */ static void quirk_disable_msi(struct pci_dev *dev) -- cgit v1.2.3 From 369b868f4a2ef89ee1c929d630058eac83015189 Mon Sep 17 00:00:00 2001 From: Vidya Sagar Date: Thu, 26 Nov 2020 00:52:34 +0530 Subject: PCI: tegra: Move "dbi" accesses to post common DWC initialization commit a0fd361db8e5 ("PCI: dwc: Move "dbi", "dbi2", and "addr_space" resource setup into common code") moved the code that sets up dbi_base to DWC common code thereby creating a requirement to not access the "dbi" region before calling common DWC initialization code. But, Tegra194 already had some code that programs some of the "dbi" registers resulting in system crash. This patch addresses that issue by refactoring the code to have accesses to the "dbi" region only after common DWC initialization. Link: https://lore.kernel.org/r/20201125192234.2270-1-vidyas@nvidia.com Fixes: a0fd361db8e5 ("PCI: dwc: Move "dbi", "dbi2", and "addr_space" resource setup into common code") Tested-by: Thierry Reding Signed-off-by: Vidya Sagar Signed-off-by: Lorenzo Pieralisi Acked-by: Thierry Reding --- drivers/pci/controller/dwc/pcie-tegra194.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index fa54d9aaa430..9ad6e7d6fb99 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -859,6 +859,16 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp) struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); u32 val; + if (!pcie->pcie_cap_base) + pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci, + PCI_CAP_ID_EXP); + + /* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */ + if (!pcie->supports_clkreq) { + disable_aspm_l11(pcie); + disable_aspm_l12(pcie); + } + val = dw_pcie_readl_dbi(pci, PCI_IO_BASE); val &= ~(IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8); dw_pcie_writel_dbi(pci, PCI_IO_BASE, val); @@ -1382,15 +1392,6 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie, reset_control_deassert(pcie->core_rst); - pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci, - PCI_CAP_ID_EXP); - - /* Disable ASPM-L1SS advertisement as there is no CLKREQ routing */ - if (!pcie->supports_clkreq) { - disable_aspm_l11(pcie); - disable_aspm_l12(pcie); - } - return ret; fail_phy: -- cgit v1.2.3 From d5353c00cfd93b1c03fb16a5e6b5b49026534755 Mon Sep 17 00:00:00 2001 From: Vidya Sagar Date: Thu, 26 Nov 2020 00:55:54 +0530 Subject: PCI: tegra: Read "dbi" base address to program in application logic PCIe controller in Tegra194 requires the "dbi" region base address to be programmed in one of the application logic registers to enable CPU access to the "dbi" region. But, commit a0fd361db8e5 ("PCI: dwc: Move "dbi", "dbi2", and "addr_space" resource setup into common code") moved the code that reads the whereabouts of "dbi" region to the common code causing the existing code in pcie-tegra194.c file to program NULL in the application logic registers. This is causing null pointer dereference when the "dbi" registers are accessed. This issue is fixed by explicitly reading the "dbi" base address from DT node. Link: https://lore.kernel.org/r/20201125192554.5401-1-vidyas@nvidia.com Fixes: a0fd361db8e5 ("PCI: dwc: Move "dbi", "dbi2", and "addr_space" resource setup into common code") Tested-by: Thierry Reding Signed-off-by: Vidya Sagar Signed-off-by: Lorenzo Pieralisi Acked-by: Thierry Reding --- drivers/pci/controller/dwc/pcie-tegra194.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 9ad6e7d6fb99..648e731bccfa 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1063,9 +1063,16 @@ phy_exit: static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie) { + struct platform_device *pdev = to_platform_device(pcie->dev); struct device_node *np = pcie->dev->of_node; int ret; + pcie->dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); + if (!pcie->dbi_res) { + dev_err(pcie->dev, "Failed to find \"dbi\" region\n"); + return -ENODEV; + } + ret = of_property_read_u32(np, "nvidia,aspm-cmrt-us", &pcie->aspm_cmrt); if (ret < 0) { dev_info(pcie->dev, "Failed to read ASPM T_cmrt: %d\n", ret); -- cgit v1.2.3 From 6b6fafc1abc7c046c57732a8cd1d2443fd60b370 Mon Sep 17 00:00:00 2001 From: Vidya Sagar Date: Thu, 3 Dec 2020 19:04:47 +0530 Subject: PCI: tegra: Fix ASPM-L1SS advertisement disable code If the absence of CLKREQ# signal is indicated by the absence of "supports-clkreq" in the device-tree node, current driver is disabling the advertisement of ASPM-L1 Sub-States *before* the ASPM-L1 Sub-States offset is correctly initialized. Since default value of the ASPM-L1SS offset is zero, this is causing the Vendor-ID wrongly programmed to 0x10d2 instead of Nvidia's 0x10de thereby the quirks applicable for Tegra194 are not being applied. This patch fixes this issue by refactoring the code that disables the ASPM-L1SS advertisement. Link: https://lore.kernel.org/r/20201203133451.17716-2-vidyas@nvidia.com Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") Signed-off-by: Vidya Sagar Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-tegra194.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 648e731bccfa..4c966e9adb2b 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -863,12 +863,6 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp) pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci, PCI_CAP_ID_EXP); - /* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */ - if (!pcie->supports_clkreq) { - disable_aspm_l11(pcie); - disable_aspm_l12(pcie); - } - val = dw_pcie_readl_dbi(pci, PCI_IO_BASE); val &= ~(IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8); dw_pcie_writel_dbi(pci, PCI_IO_BASE, val); @@ -897,6 +891,12 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp) init_host_aspm(pcie); + /* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */ + if (!pcie->supports_clkreq) { + disable_aspm_l11(pcie); + disable_aspm_l12(pcie); + } + val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF); val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL; dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val); -- cgit v1.2.3 From 01254b6d6bb3e202650817ccb0a1386b5afd7e51 Mon Sep 17 00:00:00 2001 From: Vidya Sagar Date: Thu, 3 Dec 2020 19:04:48 +0530 Subject: PCI: tegra: Set DesignWare IP version Set the DesignWare IP version for Tegra194 to 0x490A. This would be used by the DesigWare sub-system to do any version specific configuration (Ex:- TD bit programming for ECRC). Link: https://lore.kernel.org/r/20201203133451.17716-3-vidyas@nvidia.com Tested-by: Thierry Reding Signed-off-by: Vidya Sagar Signed-off-by: Lorenzo Pieralisi Acked-by: Thierry Reding --- drivers/pci/controller/dwc/pcie-tegra194.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 4c966e9adb2b..59163b735c96 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1984,6 +1984,7 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev) pci->ops = &tegra_dw_pcie_ops; pci->n_fts[0] = N_FTS_VAL; pci->n_fts[1] = FTS_VAL; + pci->version = 0x490A; pp = &pci->pp; pp->num_vectors = MAX_MSI_IRQS; -- cgit v1.2.3 From b8f0d67149acf762861f9b02bc3d5bd49b2f72bd Mon Sep 17 00:00:00 2001 From: Vidya Sagar Date: Thu, 3 Dec 2020 19:04:49 +0530 Subject: PCI: tegra: Continue unconfig sequence even if parts fail Currently the driver checks for error value of different APIs during the uninitialization sequence. It just returns from there if there is any error observed for one of those calls. Comparatively it is better to continue the uninitialization sequence irrespective of whether some of them are returning error. That way, it is more closer to complete uninitialization. Link: https://lore.kernel.org/r/20201203133451.17716-4-vidyas@nvidia.com Tested-by: Thierry Reding Signed-off-by: Vidya Sagar Signed-off-by: Lorenzo Pieralisi Acked-by: Thierry Reding --- drivers/pci/controller/dwc/pcie-tegra194.c | 39 ++++++++++++------------------ 1 file changed, 15 insertions(+), 24 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 59163b735c96..471c6d725c70 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1415,43 +1415,32 @@ fail_slot_reg_en: return ret; } -static int __deinit_controller(struct tegra_pcie_dw *pcie) +static void tegra_pcie_unconfig_controller(struct tegra_pcie_dw *pcie) { int ret; ret = reset_control_assert(pcie->core_rst); - if (ret) { - dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n", - ret); - return ret; - } + if (ret) + dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n", ret); tegra_pcie_disable_phy(pcie); ret = reset_control_assert(pcie->core_apb_rst); - if (ret) { + if (ret) dev_err(pcie->dev, "Failed to assert APB reset: %d\n", ret); - return ret; - } clk_disable_unprepare(pcie->core_clk); ret = regulator_disable(pcie->pex_ctl_supply); - if (ret) { + if (ret) dev_err(pcie->dev, "Failed to disable regulator: %d\n", ret); - return ret; - } tegra_pcie_disable_slot_regulators(pcie); ret = tegra_pcie_bpmp_set_ctrl_state(pcie, false); - if (ret) { + if (ret) dev_err(pcie->dev, "Failed to disable controller %d: %d\n", pcie->cid, ret); - return ret; - } - - return ret; } static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie) @@ -1475,7 +1464,8 @@ static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie) return 0; fail_host_init: - return __deinit_controller(pcie); + tegra_pcie_unconfig_controller(pcie); + return ret; } static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie) @@ -1544,13 +1534,12 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) appl_writel(pcie, data, APPL_PINMUX); } -static int tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie) +static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie) { tegra_pcie_downstream_dev_to_D0(pcie); dw_pcie_host_deinit(&pcie->pci.pp); tegra_pcie_dw_pme_turnoff(pcie); - - return __deinit_controller(pcie); + tegra_pcie_unconfig_controller(pcie); } static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie) @@ -2197,8 +2186,9 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev) PORT_LOGIC_MSI_CTRL_INT_0_EN); tegra_pcie_downstream_dev_to_D0(pcie); tegra_pcie_dw_pme_turnoff(pcie); + tegra_pcie_unconfig_controller(pcie); - return __deinit_controller(pcie); + return 0; } static int tegra_pcie_dw_resume_noirq(struct device *dev) @@ -2226,7 +2216,8 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev) return 0; fail_host_init: - return __deinit_controller(pcie); + tegra_pcie_unconfig_controller(pcie); + return ret; } static int tegra_pcie_dw_resume_early(struct device *dev) @@ -2264,7 +2255,7 @@ static void tegra_pcie_dw_shutdown(struct platform_device *pdev) disable_irq(pcie->pci.pp.msi_irq); tegra_pcie_dw_pme_turnoff(pcie); - __deinit_controller(pcie); + tegra_pcie_unconfig_controller(pcie); } static const struct tegra_pcie_dw_of_data tegra_pcie_dw_rc_of_data = { -- cgit v1.2.3 From 3d710af75bcdea2e9cb8cdb2f7663cef7b133f5e Mon Sep 17 00:00:00 2001 From: Vidya Sagar Date: Thu, 3 Dec 2020 19:04:50 +0530 Subject: PCI: tegra: Check return value of tegra_pcie_init_controller() The return value of tegra_pcie_init_controller() must be checked before PCIe link up check and registering debugfs entries subsequently as it doesn't make sense to do these when the controller initialization itself has failed. Link: https://lore.kernel.org/r/20201203133451.17716-5-vidyas@nvidia.com Tested-by: Thierry Reding Signed-off-by: Vidya Sagar Signed-off-by: Lorenzo Pieralisi Acked-by: Thierry Reding --- drivers/pci/controller/dwc/pcie-tegra194.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 471c6d725c70..f4109d71f20b 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1563,7 +1563,11 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie) goto fail_pm_get_sync; } - tegra_pcie_init_controller(pcie); + ret = tegra_pcie_init_controller(pcie); + if (ret < 0) { + dev_err(dev, "Failed to initialize controller: %d\n", ret); + goto fail_pm_get_sync; + } pcie->link_state = tegra_pcie_dw_link_up(&pcie->pci); if (!pcie->link_state) { -- cgit v1.2.3 From cf68e3b7a6b75d8f0e68c80fb353cde1878ef682 Mon Sep 17 00:00:00 2001 From: Vidya Sagar Date: Thu, 3 Dec 2020 19:04:51 +0530 Subject: PCI: tegra: Disable LTSSM during L2 entry PCIe cards like Marvell SATA controller and some of the Samsung NVMe drives don't support taking the link to L2 state. When the link doesn't go to L2 state, Tegra194 requires the LTSSM to be disabled to allow PHY to start the next link up process cleanly during suspend/resume sequence. Failing to disable LTSSM results in the PCIe link not coming up in the next resume cycle. Link: https://lore.kernel.org/r/20201203133451.17716-6-vidyas@nvidia.com Tested-by: Thierry Reding Signed-off-by: Vidya Sagar Signed-off-by: Lorenzo Pieralisi Acked-by: Thierry Reding --- drivers/pci/controller/dwc/pcie-tegra194.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index f4109d71f20b..5597b2a49598 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1506,6 +1506,14 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) data &= ~APPL_PINMUX_PEX_RST; appl_writel(pcie, data, APPL_PINMUX); + /* + * Some cards do not go to detect state even after de-asserting + * PERST#. So, de-assert LTSSM to bring link to detect state. + */ + data = readl(pcie->appl_base + APPL_CTRL); + data &= ~APPL_CTRL_LTSSM_EN; + writel(data, pcie->appl_base + APPL_CTRL); + err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, data, ((data & @@ -1513,14 +1521,8 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) APPL_DEBUG_LTSSM_STATE_SHIFT) == LTSSM_STATE_PRE_DETECT, 1, LTSSM_TIMEOUT); - if (err) { + if (err) dev_info(pcie->dev, "Link didn't go to detect state\n"); - } else { - /* Disable LTSSM after link is in detect state */ - data = appl_readl(pcie, APPL_CTRL); - data &= ~APPL_CTRL_LTSSM_EN; - appl_writel(pcie, data, APPL_CTRL); - } } /* * DBI registers may not be accessible after this as PLL-E would be -- cgit v1.2.3 From e1dd639e374a1345c63eb7e8931e08de7cb8f904 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Tue, 8 Dec 2020 17:44:01 +0530 Subject: PCI: qcom: Add SM8250 SoC support The PCIe IP (rev 1.9.0) on SM8250 SoC is similar to the one used on SDM845. Hence the support is added reusing the members of ops_2_7_0. The key difference between ops_2_7_0 and ops_1_9_0 is the config_sid callback, which will be added in successive commit. Link: https://lore.kernel.org/r/20201208121402.178011-3-mani@kernel.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Reviewed-by: Bjorn Andersson --- drivers/pci/controller/dwc/pcie-qcom.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index e49791c4f846..750ff7378870 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1348,6 +1348,16 @@ static const struct qcom_pcie_ops ops_2_7_0 = { .post_deinit = qcom_pcie_post_deinit_2_7_0, }; +/* Qcom IP rev.: 1.9.0 */ +static const struct qcom_pcie_ops ops_1_9_0 = { + .get_resources = qcom_pcie_get_resources_2_7_0, + .init = qcom_pcie_init_2_7_0, + .deinit = qcom_pcie_deinit_2_7_0, + .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable, + .post_init = qcom_pcie_post_init_2_7_0, + .post_deinit = qcom_pcie_post_deinit_2_7_0, +}; + static const struct dw_pcie_ops dw_pcie_ops = { .link_up = qcom_pcie_link_up, .start_link = qcom_pcie_start_link, @@ -1446,6 +1456,7 @@ static const struct of_device_id qcom_pcie_match[] = { { .compatible = "qcom,pcie-ipq4019", .data = &ops_2_4_0 }, { .compatible = "qcom,pcie-qcs404", .data = &ops_2_4_0 }, { .compatible = "qcom,pcie-sdm845", .data = &ops_2_7_0 }, + { .compatible = "qcom,pcie-sm8250", .data = &ops_1_9_0 }, { } }; -- cgit v1.2.3 From 4c9398822106c366d88c8c68ddf44bd371d39961 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Tue, 8 Dec 2020 17:44:02 +0530 Subject: PCI: qcom: Add support for configuring BDF to SID mapping for SM8250 For SM8250, we need to write the BDF to SID mapping in PCIe controller register space for proper working. This is accomplished by extracting the BDF and SID values from "iommu-map" property in DT and writing those in the register address calculated from the hash value of BDF. In case of collisions, the index of the next entry will also be written. For the sake of it, let's introduce a "config_sid" callback and do it conditionally for SM8250. Link: https://lore.kernel.org/r/20201208121402.178011-4-mani@kernel.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Lorenzo Pieralisi Reviewed-by: Bjorn Andersson --- drivers/pci/controller/dwc/Kconfig | 1 + drivers/pci/controller/dwc/pcie-qcom.c | 88 ++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index 9ee1e248e744..dd4596bdda49 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -174,6 +174,7 @@ config PCIE_QCOM depends on OF && (ARCH_QCOM || COMPILE_TEST) depends on PCI_MSI_IRQ_DOMAIN select PCIE_DW_HOST + select CRC8 help Say Y here to enable PCIe controller support on Qualcomm SoCs. The PCIe controller uses the DesignWare core plus Qualcomm-specific diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 750ff7378870..affa2713bf80 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -57,6 +58,7 @@ #define PCIE20_PARF_SID_OFFSET 0x234 #define PCIE20_PARF_BDF_TRANSLATE_CFG 0x24C #define PCIE20_PARF_DEVICE_TYPE 0x1000 +#define PCIE20_PARF_BDF_TO_SID_TABLE_N 0x2000 #define PCIE20_ELBI_SYS_CTRL 0x04 #define PCIE20_ELBI_SYS_CTRL_LT_ENABLE BIT(0) @@ -97,6 +99,9 @@ #define QCOM_PCIE_2_1_0_MAX_SUPPLY 3 #define QCOM_PCIE_2_1_0_MAX_CLOCKS 5 + +#define QCOM_PCIE_CRC8_POLYNOMIAL (BIT(2) | BIT(1) | BIT(0)) + struct qcom_pcie_resources_2_1_0 { struct clk_bulk_data clks[QCOM_PCIE_2_1_0_MAX_CLOCKS]; struct reset_control *pci_reset; @@ -179,6 +184,7 @@ struct qcom_pcie_ops { void (*deinit)(struct qcom_pcie *pcie); void (*post_deinit)(struct qcom_pcie *pcie); void (*ltssm_enable)(struct qcom_pcie *pcie); + int (*config_sid)(struct qcom_pcie *pcie); }; struct qcom_pcie { @@ -1258,6 +1264,77 @@ static int qcom_pcie_link_up(struct dw_pcie *pci) return !!(val & PCI_EXP_LNKSTA_DLLLA); } +static int qcom_pcie_config_sid_sm8250(struct qcom_pcie *pcie) +{ + /* iommu map structure */ + struct { + u32 bdf; + u32 phandle; + u32 smmu_sid; + u32 smmu_sid_len; + } *map; + void __iomem *bdf_to_sid_base = pcie->parf + PCIE20_PARF_BDF_TO_SID_TABLE_N; + struct device *dev = pcie->pci->dev; + u8 qcom_pcie_crc8_table[CRC8_TABLE_SIZE]; + int i, nr_map, size = 0; + u32 smmu_sid_base; + + of_get_property(dev->of_node, "iommu-map", &size); + if (!size) + return 0; + + map = kzalloc(size, GFP_KERNEL); + if (!map) + return -ENOMEM; + + of_property_read_u32_array(dev->of_node, + "iommu-map", (u32 *)map, size / sizeof(u32)); + + nr_map = size / (sizeof(*map)); + + crc8_populate_msb(qcom_pcie_crc8_table, QCOM_PCIE_CRC8_POLYNOMIAL); + + /* Registers need to be zero out first */ + memset_io(bdf_to_sid_base, 0, CRC8_TABLE_SIZE * sizeof(u32)); + + /* Extract the SMMU SID base from the first entry of iommu-map */ + smmu_sid_base = map[0].smmu_sid; + + /* Look for an available entry to hold the mapping */ + for (i = 0; i < nr_map; i++) { + u16 bdf_be = cpu_to_be16(map[i].bdf); + u32 val; + u8 hash; + + hash = crc8(qcom_pcie_crc8_table, (u8 *)&bdf_be, sizeof(bdf_be), + 0); + + val = readl(bdf_to_sid_base + hash * sizeof(u32)); + + /* If the register is already populated, look for next available entry */ + while (val) { + u8 current_hash = hash++; + u8 next_mask = 0xff; + + /* If NEXT field is NULL then update it with next hash */ + if (!(val & next_mask)) { + val |= (u32)hash; + writel(val, bdf_to_sid_base + current_hash * sizeof(u32)); + } + + val = readl(bdf_to_sid_base + hash * sizeof(u32)); + } + + /* BDF [31:16] | SID [15:8] | NEXT [7:0] */ + val = map[i].bdf << 16 | (map[i].smmu_sid - smmu_sid_base) << 8 | 0; + writel(val, bdf_to_sid_base + hash * sizeof(u32)); + } + + kfree(map); + + return 0; +} + static int qcom_pcie_host_init(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); @@ -1282,8 +1359,18 @@ static int qcom_pcie_host_init(struct pcie_port *pp) qcom_ep_reset_deassert(pcie); + if (pcie->ops->config_sid) { + ret = pcie->ops->config_sid(pcie); + if (ret) + goto err; + } + return 0; +err: + qcom_ep_reset_assert(pcie); + if (pcie->ops->post_deinit) + pcie->ops->post_deinit(pcie); err_disable_phy: phy_power_off(pcie->phy); err_deinit: @@ -1356,6 +1443,7 @@ static const struct qcom_pcie_ops ops_1_9_0 = { .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable, .post_init = qcom_pcie_post_init_2_7_0, .post_deinit = qcom_pcie_post_deinit_2_7_0, + .config_sid = qcom_pcie_config_sid_sm8250, }; static const struct dw_pcie_ops dw_pcie_ops = { -- cgit v1.2.3 From 660c486590aa4190969653218643b3a4e5660f2b Mon Sep 17 00:00:00 2001 From: Vidya Sagar Date: Tue, 17 Nov 2020 22:23:12 +0530 Subject: PCI: dwc: Set 32-bit DMA mask for MSI target address allocation Set DMA mask to 32-bit while allocating the MSI target address so that the address is usable for both 32-bit and 64-bit MSI capable devices. Throw a warning if it fails to set the mask to 32-bit to alert that devices that are only 32-bit MSI capable may not work properly. Link: https://lore.kernel.org/r/20201117165312.25847-1-vidyas@nvidia.com Signed-off-by: Vidya Sagar Signed-off-by: Lorenzo Pieralisi Reviewed-by: Robin Murphy --- drivers/pci/controller/dwc/pcie-designware-host.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 99ef808a40a9..516b151e0ef3 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -396,6 +396,14 @@ int dw_pcie_host_init(struct pcie_port *pp) dw_chained_msi_isr, pp); + ret = dma_set_mask(pci->dev, DMA_BIT_MASK(32)); + if (!ret) { + dev_warn(pci->dev, + "Failed to set DMA mask to 32-bit. " + "Devices with only 32-bit MSI support" + " may not work properly\n"); + } + pp->msi_data = dma_map_single_attrs(pci->dev, &pp->msi_msg, sizeof(pp->msi_msg), DMA_FROM_DEVICE, -- cgit v1.2.3