Re: [PATCH V4] PCI: Add MCFG quirks for Tegra194 host controllers

2021-04-16 Thread Bjorn Helgaas
On Fri, Apr 16, 2021 at 07:15:37PM +0530, Vidya Sagar wrote:
> The PCIe controller in Tegra194 SoC is not completely ECAM-compliant.
> With the current hardware design limitations in place, ECAM can be enabled
> only for one controller (C5 controller to be precise) with bus numbers
> starting from 160 instead of 0. A different approach is taken to avoid this
> abnormal way of enabling ECAM for just one controller but to enable
> configuration space access for all the other controllers. In this approach,
> ops are added through MCFG quirk mechanism which access the configuration
> spaces by dynamically programming iATU (internal AddressTranslation Unit)
> to generate respective configuration accesses just like the way it is
> done in DesignWare core sub-system.
> This issue is specific to Tegra194 and it would be fixed in the future
> generations of Tegra SoCs.
> 
> Signed-off-by: Vidya Sagar 

Applied to pci/tegra for v5.13, thanks!

> ---
> V4:
> * Addressed Bjorn's review comments
> * Rebased changes on top of Lorenzo's pci/dwc branch
> 
> V3:
> * Removed MCFG address hardcoding in pci_mcfg.c file
> * Started using 'dbi_base' for accessing root port's own config space
> * and using 'config_base' for accessing config space of downstream hierarchy
> 
> V2:
> * Fixed build issues reported by kbuild test bot
> 
>  drivers/acpi/pci_mcfg.c|   7 ++
>  drivers/pci/controller/dwc/Makefile|   2 +-
>  drivers/pci/controller/dwc/pcie-tegra194.c | 103 +
>  include/linux/pci-ecam.h   |   1 +
>  4 files changed, 112 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
> index 95f23acd5b80..53cab975f612 100644
> --- a/drivers/acpi/pci_mcfg.c
> +++ b/drivers/acpi/pci_mcfg.c
> @@ -116,6 +116,13 @@ static struct mcfg_fixup mcfg_quirks[] = {
>   THUNDER_ECAM_QUIRK(2, 12),
>   THUNDER_ECAM_QUIRK(2, 13),
>  
> + { "NVIDIA", "TEGRA194", 1, 0, MCFG_BUS_ANY, _pcie_ops},
> + { "NVIDIA", "TEGRA194", 1, 1, MCFG_BUS_ANY, _pcie_ops},
> + { "NVIDIA", "TEGRA194", 1, 2, MCFG_BUS_ANY, _pcie_ops},
> + { "NVIDIA", "TEGRA194", 1, 3, MCFG_BUS_ANY, _pcie_ops},
> + { "NVIDIA", "TEGRA194", 1, 4, MCFG_BUS_ANY, _pcie_ops},
> + { "NVIDIA", "TEGRA194", 1, 5, MCFG_BUS_ANY, _pcie_ops},
> +
>  #define XGENE_V1_ECAM_MCFG(rev, seg) \
>   {"APM   ", "XGENE   ", rev, seg, MCFG_BUS_ANY, \
>   _v1_pcie_ecam_ops }
> diff --git a/drivers/pci/controller/dwc/Makefile 
> b/drivers/pci/controller/dwc/Makefile
> index 625f6aaeb5b8..2da826ef18ac 100644
> --- a/drivers/pci/controller/dwc/Makefile
> +++ b/drivers/pci/controller/dwc/Makefile
> @@ -18,7 +18,6 @@ obj-$(CONFIG_PCIE_INTEL_GW) += pcie-intel-gw.o
>  obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o
>  obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
>  obj-$(CONFIG_PCI_MESON) += pci-meson.o
> -obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o
>  obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
>  obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
>  
> @@ -35,4 +34,5 @@ obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
>  ifdef CONFIG_PCI
>  obj-$(CONFIG_ARM64) += pcie-al.o
>  obj-$(CONFIG_ARM64) += pcie-hisi.o
> +obj-$(CONFIG_ARM64) += pcie-tegra194.o
>  endif
> diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
> b/drivers/pci/controller/dwc/pcie-tegra194.c
> index 6fa216e52d14..cb38e94a3033 100644
> --- a/drivers/pci/controller/dwc/pcie-tegra194.c
> +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
> @@ -22,6 +22,8 @@
>  #include 
>  #include 
>  #include 
> +#include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -311,6 +313,104 @@ struct tegra_pcie_dw_of_data {
>   enum dw_pcie_device_mode mode;
>  };
>  
> +#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
> +struct tegra194_pcie_ecam  {
> + void __iomem *config_base;
> + void __iomem *iatu_base;
> + void __iomem *dbi_base;
> +};
> +
> +static int tegra194_acpi_init(struct pci_config_window *cfg)
> +{
> + struct device *dev = cfg->parent;
> + struct tegra194_pcie_ecam *pcie_ecam;
> +
> + pcie_ecam = devm_kzalloc(dev, sizeof(*pcie_ecam), GFP_KERNEL);
> + if (!pcie_ecam)
> + return -ENOMEM;
> +
> + pcie_ecam->config_base = cfg->win;
> + pcie_ecam->iatu_base = cfg->win + SZ_256K;
> + pcie_ecam->dbi_base = cfg->win + SZ_512K;
> + cfg->priv = pcie_ecam;
> +
> + return 0;
> +}
> +
> +static void atu_reg_write(struct tegra194_pcie_ecam *pcie_ecam, int index,
> +   u32 val, u32 reg)
> +{
> + u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
> +
> + writel(val, pcie_ecam->iatu_base + offset + reg);
> +}
> +
> +static void program_outbound_atu(struct tegra194_pcie_ecam *pcie_ecam,
> +  int index, int type, u64 cpu_addr,
> +  u64 pci_addr, u64 size)
> +{
> + atu_reg_write(pcie_ecam, index, lower_32_bits(cpu_addr),
> +   

[PATCH V4] PCI: Add MCFG quirks for Tegra194 host controllers

2021-04-16 Thread Vidya Sagar
The PCIe controller in Tegra194 SoC is not completely ECAM-compliant.
With the current hardware design limitations in place, ECAM can be enabled
only for one controller (C5 controller to be precise) with bus numbers
starting from 160 instead of 0. A different approach is taken to avoid this
abnormal way of enabling ECAM for just one controller but to enable
configuration space access for all the other controllers. In this approach,
ops are added through MCFG quirk mechanism which access the configuration
spaces by dynamically programming iATU (internal AddressTranslation Unit)
to generate respective configuration accesses just like the way it is
done in DesignWare core sub-system.
This issue is specific to Tegra194 and it would be fixed in the future
generations of Tegra SoCs.

Signed-off-by: Vidya Sagar 
---
V4:
* Addressed Bjorn's review comments
* Rebased changes on top of Lorenzo's pci/dwc branch

V3:
* Removed MCFG address hardcoding in pci_mcfg.c file
* Started using 'dbi_base' for accessing root port's own config space
* and using 'config_base' for accessing config space of downstream hierarchy

V2:
* Fixed build issues reported by kbuild test bot

 drivers/acpi/pci_mcfg.c|   7 ++
 drivers/pci/controller/dwc/Makefile|   2 +-
 drivers/pci/controller/dwc/pcie-tegra194.c | 103 +
 include/linux/pci-ecam.h   |   1 +
 4 files changed, 112 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
index 95f23acd5b80..53cab975f612 100644
--- a/drivers/acpi/pci_mcfg.c
+++ b/drivers/acpi/pci_mcfg.c
@@ -116,6 +116,13 @@ static struct mcfg_fixup mcfg_quirks[] = {
THUNDER_ECAM_QUIRK(2, 12),
THUNDER_ECAM_QUIRK(2, 13),
 
+   { "NVIDIA", "TEGRA194", 1, 0, MCFG_BUS_ANY, _pcie_ops},
+   { "NVIDIA", "TEGRA194", 1, 1, MCFG_BUS_ANY, _pcie_ops},
+   { "NVIDIA", "TEGRA194", 1, 2, MCFG_BUS_ANY, _pcie_ops},
+   { "NVIDIA", "TEGRA194", 1, 3, MCFG_BUS_ANY, _pcie_ops},
+   { "NVIDIA", "TEGRA194", 1, 4, MCFG_BUS_ANY, _pcie_ops},
+   { "NVIDIA", "TEGRA194", 1, 5, MCFG_BUS_ANY, _pcie_ops},
+
 #define XGENE_V1_ECAM_MCFG(rev, seg) \
{"APM   ", "XGENE   ", rev, seg, MCFG_BUS_ANY, \
_v1_pcie_ecam_ops }
diff --git a/drivers/pci/controller/dwc/Makefile 
b/drivers/pci/controller/dwc/Makefile
index 625f6aaeb5b8..2da826ef18ac 100644
--- a/drivers/pci/controller/dwc/Makefile
+++ b/drivers/pci/controller/dwc/Makefile
@@ -18,7 +18,6 @@ obj-$(CONFIG_PCIE_INTEL_GW) += pcie-intel-gw.o
 obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o
 obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
 obj-$(CONFIG_PCI_MESON) += pci-meson.o
-obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o
 obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
 obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
 
@@ -35,4 +34,5 @@ obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
 ifdef CONFIG_PCI
 obj-$(CONFIG_ARM64) += pcie-al.o
 obj-$(CONFIG_ARM64) += pcie-hisi.o
+obj-$(CONFIG_ARM64) += pcie-tegra194.o
 endif
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 6fa216e52d14..cb38e94a3033 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -22,6 +22,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -311,6 +313,104 @@ struct tegra_pcie_dw_of_data {
enum dw_pcie_device_mode mode;
 };
 
+#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
+struct tegra194_pcie_ecam  {
+   void __iomem *config_base;
+   void __iomem *iatu_base;
+   void __iomem *dbi_base;
+};
+
+static int tegra194_acpi_init(struct pci_config_window *cfg)
+{
+   struct device *dev = cfg->parent;
+   struct tegra194_pcie_ecam *pcie_ecam;
+
+   pcie_ecam = devm_kzalloc(dev, sizeof(*pcie_ecam), GFP_KERNEL);
+   if (!pcie_ecam)
+   return -ENOMEM;
+
+   pcie_ecam->config_base = cfg->win;
+   pcie_ecam->iatu_base = cfg->win + SZ_256K;
+   pcie_ecam->dbi_base = cfg->win + SZ_512K;
+   cfg->priv = pcie_ecam;
+
+   return 0;
+}
+
+static void atu_reg_write(struct tegra194_pcie_ecam *pcie_ecam, int index,
+ u32 val, u32 reg)
+{
+   u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
+
+   writel(val, pcie_ecam->iatu_base + offset + reg);
+}
+
+static void program_outbound_atu(struct tegra194_pcie_ecam *pcie_ecam,
+int index, int type, u64 cpu_addr,
+u64 pci_addr, u64 size)
+{
+   atu_reg_write(pcie_ecam, index, lower_32_bits(cpu_addr),
+ PCIE_ATU_LOWER_BASE);
+   atu_reg_write(pcie_ecam, index, upper_32_bits(cpu_addr),
+ PCIE_ATU_UPPER_BASE);
+   atu_reg_write(pcie_ecam, index, lower_32_bits(pci_addr),
+ PCIE_ATU_LOWER_TARGET);
+   atu_reg_write(pcie_ecam, index, lower_32_bits(cpu_addr