Skip to contentSkip to conversation

ARM: tegra: Add PCIe device tree support

PATCH Superseded Thierry Reding 5 participants 96 messages Jun 11, 2012 – Jun 27, 2012

Subsystems (7)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

v2 cover ARM: tegra: Add PCIe device tree support

This patch series adds support for device tree based probing of the PCIe controller found on Tegra SoCs.

Patches 1 and 2 keep the pci_fixup_irqs() and ARM-specific pci_common_init() functions around after init. This is required to support driver probe deferral, which may cause built-in drivers to be probed after __init data has already been freed.

Patch 3 allows a driver's probe function to pass per-controller private data when calling the pci_common_init() function.

Patch 4 is trivial and has already been Acked-by: Stephen Warren before.

Patch 5 rewrites PCIe support as a driver and switches the Harmony and TrimSlice boards to add the proper platform device instead of calling the tegra_pcie_init() function. Patch 6 adds MSI support as an IRQ domain.

Patch 7 finally implements device tree support and patches 8, 9 and 10 move the Harmony and TrimSlice boards over to use information provided in the DTS to probe the PCIe controller.

Thierry

Thierry Reding (10):
PCI: Keep pci_fixup_irqs() around after init
ARM: pci: Keep pci_common_init() around after init
ARM: pci: Allow passing per-controller private data
ARM: tegra: Move tegra_pcie_xclk_clamp() to PMC
ARM: tegra: Rewrite PCIe support as a driver
ARM: tegra: pcie: Add MSI support
ARM: tegra: pcie: Add device tree support
ARM: tegra: harmony: Initialize regulators from DT
ARM: tegra: harmony: Initialize PCIe from DT
ARM: tegra: trimslice: Initialize PCIe from DT

 .../devicetree/bindings/pci/tegra-pcie.txt         |   23 +
 arch/arm/boot/dts/tegra-harmony.dts                |   98 +++
 arch/arm/boot/dts/tegra-trimslice.dts              |   20 +
 arch/arm/boot/dts/tegra20.dtsi                     |    9 +
 arch/arm/include/asm/mach/pci.h                    |    1 +
 arch/arm/kernel/bios32.c                           |    7 +-
 arch/arm/mach-tegra/Kconfig                        |    1 +
 arch/arm/mach-tegra/board-dt-tegra20.c             |   35 +-
 arch/arm/mach-tegra/board-harmony-pcie.c           |   38 +-
 arch/arm/mach-tegra/board-harmony.c                |    1 +
 arch/arm/mach-tegra/board-harmony.h                |    1 +
 arch/arm/mach-tegra/board-trimslice.c              |   18 +-
 arch/arm/mach-tegra/board.h                        |    2 +-
 arch/arm/mach-tegra/devices.c                      |   32 +
 arch/arm/mach-tegra/devices.h                      |    1 +
 arch/arm/mach-tegra/include/mach/iomap.h           |    6 +
 arch/arm/mach-tegra/include/mach/irqs.h            |    5 +-
 arch/arm/mach-tegra/include/mach/pci-tegra.h       |   29 +
 arch/arm/mach-tegra/pcie.c                         |  926 +++++++++++++++-----
 arch/arm/mach-tegra/pmc.c                          |   16 +
 arch/arm/mach-tegra/pmc.h                          |    1 +
 drivers/pci/setup-irq.c                            |    4 +-
 22 files changed, 983 insertions(+), 291 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pci/tegra-pcie.txt
 create mode 100644 arch/arm/mach-tegra/include/mach/pci-tegra.h
Signature · 1 line
1.7.10.4
#1 lore raw

PATCH v2 1/10 PCI: Keep pci_fixup_irqs() around after init

---
Changes in v2:
- use __devinit annotations

 drivers/pci/setup-irq.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/pci/setup-irq.c +2 -2
index eb219a1..f0bcd56 100644
@@ -18,7 +18,7 @@
 #include <linux/cache.h>
 
 
-static void __init
+static void __devinit
 pdev_fixup_irq(struct pci_dev *dev,
 	       u8 (*swizzle)(struct pci_dev *, u8 *),
 	       int (*map_irq)(const struct pci_dev *, u8, u8))
@@ -54,7 +54,7 @@ pdev_fixup_irq(struct pci_dev *dev,
 	pcibios_update_irq(dev, irq);
 }
 
-void __init
+void __devinit
 pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
 	       int (*map_irq)(const struct pci_dev *, u8, u8))
 {
Signature · 1 line
1.7.10.4
#2 lore raw

PATCH v2 2/10 ARM: pci: Keep pci_common_init() around after init

In reply to Thierry Reding

---
Changes in v2:
- use __devinit annotations

---
 arch/arm/kernel/bios32.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm/kernel/bios32.c +2 -2
index 2555250..c9d28dd 100644
@@ -423,7 +423,7 @@ static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 	return irq;
 }
 
-static void __init pcibios_init_hw(struct hw_pci *hw, struct list_head *head)
+static void __devinit pcibios_init_hw(struct hw_pci *hw, struct list_head *head)
 {
 	struct pci_sys_data *sys = NULL;
 	int ret;
@@ -472,7 +472,7 @@ static void __init pcibios_init_hw(struct hw_pci *hw, struct list_head *head)
 	}
 }
 
-void __init pci_common_init(struct hw_pci *hw)
+void __devinit pci_common_init(struct hw_pci *hw)
 {
 	struct pci_sys_data *sys;
 	LIST_HEAD(head);
Signature · 1 line
1.7.10.4
#3 lore raw

PATCH v2 3/10 ARM: pci: Allow passing per-controller private data

In reply to Thierry Reding

In order to allow drivers to specify private data for each controller, this commit adds a private_data field to the struct hw_pci. This field is an array of nr_controllers pointers that will be used to initialize the private_data field of the corresponding controller's pci_sys_data structure.

---
Changes in v2:
- new patch

---
 arch/arm/include/asm/mach/pci.h |    1 +
 arch/arm/kernel/bios32.c        |    3 +++
 2 files changed, 4 insertions(+)
arch/arm/include/asm/mach/pci.h +1 -0
index 26c511f..736cb8d 100644
@@ -21,6 +21,7 @@ struct hw_pci {
 #endif
 	struct pci_ops	*ops;
 	int		nr_controllers;
+	void		**private_data;
 	int		(*setup)(int nr, struct pci_sys_data *);
 	struct pci_bus *(*scan)(int nr, struct pci_sys_data *);
 	void		(*preinit)(void);
arch/arm/kernel/bios32.c +3 -0
index c9d28dd..04858c6 100644
@@ -442,6 +442,9 @@ static void __devinit pcibios_init_hw(struct hw_pci *hw, struct list_head *head)
 		sys->map_irq = hw->map_irq;
 		INIT_LIST_HEAD(&sys->resources);
 
+		if (hw->private_data)
+			sys->private_data = hw->private_data[nr];
+
 		ret = hw->setup(nr, sys);
 
 		if (ret > 0) {
Signature · 1 line
1.7.10.4
#4 lore raw

PATCH v2 4/10 ARM: tegra: Move tegra_pcie_xclk_clamp() to PMC

In reply to Thierry Reding

The PMC code already accesses to PMC registers so it makes sense to move this function there as well. While at it, rename the function to tegra_pmc_pcie_xclk_clamp() for consistency.

---
Changes in v2:
- none

---
 arch/arm/mach-tegra/pcie.c |   30 ++++--------------------------
 arch/arm/mach-tegra/pmc.c  |   16 ++++++++++++++++
 arch/arm/mach-tegra/pmc.h  |    1 +
 3 files changed, 21 insertions(+), 26 deletions(-)
arch/arm/mach-tegra/pcie.c +4 -26
index 0e09137..fcdf8bc 100644
@@ -42,6 +42,7 @@
 #include <mach/powergate.h>
 
 #include "board.h"
+#include "pmc.h"
 
 /* register definitions */
 #define AFI_OFFSET	0x3800
@@ -145,17 +146,6 @@
 #define  PADS_PLL_CTL_TXCLKREF_DIV10		(0 << 20)
 #define  PADS_PLL_CTL_TXCLKREF_DIV5		(1 << 20)
 
-/* PMC access is required for PCIE xclk (un)clamping */
-#define PMC_SCRATCH42		0x144
-#define PMC_SCRATCH42_PCX_CLAMP	(1 << 0)
-
-static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
-
-#define pmc_writel(value, reg) \
-	__raw_writel(value, reg_pmc_base + (reg))
-#define pmc_readl(reg) \
-	__raw_readl(reg_pmc_base + (reg))
-
 /*
  * Tegra2 defines 1GB in the AXI address map for PCIe.
  *
@@ -679,18 +669,6 @@ static int tegra_pcie_enable_controller(void)
 	return 0;
 }
 
-static void tegra_pcie_xclk_clamp(bool clamp)
-{
-	u32 reg;
-
-	reg = pmc_readl(PMC_SCRATCH42) & ~PMC_SCRATCH42_PCX_CLAMP;
-
-	if (clamp)
-		reg |= PMC_SCRATCH42_PCX_CLAMP;
-
-	pmc_writel(reg, PMC_SCRATCH42);
-}
-
 static void tegra_pcie_power_off(void)
 {
 	tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
@@ -698,7 +676,7 @@ static void tegra_pcie_power_off(void)
 	tegra_periph_reset_assert(tegra_pcie.pex_clk);
 
 	tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
-	tegra_pcie_xclk_clamp(true);
+	tegra_pmc_pcie_xclk_clamp(true);
 }
 
 static int tegra_pcie_power_regate(void)
@@ -707,7 +685,7 @@ static int tegra_pcie_power_regate(void)
 
 	tegra_pcie_power_off();
 
-	tegra_pcie_xclk_clamp(true);
+	tegra_pmc_pcie_xclk_clamp(true);
 
 	tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
 	tegra_periph_reset_assert(tegra_pcie.afi_clk);
@@ -721,7 +699,7 @@ static int tegra_pcie_power_regate(void)
 
 	tegra_periph_reset_deassert(tegra_pcie.afi_clk);
 
-	tegra_pcie_xclk_clamp(false);
+	tegra_pmc_pcie_xclk_clamp(false);
 
 	clk_enable(tegra_pcie.afi_clk);
 	clk_enable(tegra_pcie.pex_clk);
arch/arm/mach-tegra/pmc.c +16 -0
index 7af6a54..399dc3a 100644
@@ -24,6 +24,10 @@
 #define PMC_CTRL		0x0
 #define PMC_CTRL_INTR_LOW	(1 << 17)
 
+/* PMC access is required for PCIE xclk (un)clamping */
+#define PMC_SCRATCH42		0x144
+#define PMC_SCRATCH42_PCX_CLAMP	(1 << 0)
+
 static inline u32 tegra_pmc_readl(u32 reg)
 {
 	return readl(IO_ADDRESS(TEGRA_PMC_BASE + reg));
@@ -74,3 +78,15 @@ void __init tegra_pmc_init(void)
 		val &= ~PMC_CTRL_INTR_LOW;
 	tegra_pmc_writel(val, PMC_CTRL);
 }
+
+void tegra_pmc_pcie_xclk_clamp(bool clamp)
+{
+	u32 reg;
+
+	reg = tegra_pmc_readl(PMC_SCRATCH42) & ~PMC_SCRATCH42_PCX_CLAMP;
+
+	if (clamp)
+		reg |= PMC_SCRATCH42_PCX_CLAMP;
+
+	tegra_pmc_writel(reg, PMC_SCRATCH42);
+}
arch/arm/mach-tegra/pmc.h +1 -0
index 8995ee4..2631c9a 100644
@@ -19,5 +19,6 @@
 #define __MACH_TEGRA_PMC_H
 
 void tegra_pmc_init(void);
+void tegra_pmc_pcie_xclk_clamp(bool clamp);
 
 #endif
Signature · 1 line
1.7.10.4
#5 lore raw

PATCH v2 5/10 ARM: tegra: Rewrite PCIe support as a driver

In reply to Thierry Reding

This commit adds a platform device driver for the PCIe controller on Tegra SOCs. Current users of the old code (TrimSlice and Harmony) are converted and now initialize and register a corresponding platform device.

---
Changes in v2:
- use struct hw_pci's new private_data field
- fix DT initialization for TrimSlice

---
 arch/arm/mach-tegra/board-dt-tegra20.c       |   15 +-
 arch/arm/mach-tegra/board-harmony-pcie.c     |   38 +-
 arch/arm/mach-tegra/board-harmony.c          |    1 +
 arch/arm/mach-tegra/board-harmony.h          |    1 +
 arch/arm/mach-tegra/board-trimslice.c        |   18 +-
 arch/arm/mach-tegra/board.h                  |    2 +-
 arch/arm/mach-tegra/devices.c                |   25 ++
 arch/arm/mach-tegra/devices.h                |    1 +
 arch/arm/mach-tegra/include/mach/iomap.h     |    6 +
 arch/arm/mach-tegra/include/mach/pci-tegra.h |   29 ++
 arch/arm/mach-tegra/pcie.c                   |  514 ++++++++++++++++----------
 11 files changed, 419 insertions(+), 231 deletions(-)
 create mode 100644 arch/arm/mach-tegra/include/mach/pci-tegra.h
arch/arm/mach-tegra/board-dt-tegra20.c +10 -5
index 9c444a0..0f29c05 100644
@@ -40,6 +40,7 @@
 
 #include <mach/iomap.h>
 #include <mach/irqs.h>
+#include <mach/pci-tegra.h>
 
 #include "board.h"
 #include "board-harmony.h"
@@ -116,13 +117,17 @@ static void __init tegra_dt_init(void)
 }
 
 #ifdef CONFIG_MACH_TRIMSLICE
+static struct tegra_pcie_pdata trimslice_pcie_pdata = {
+	.enable_ports = {
+		[0] = true,
+		[1] = true,
+	},
+};
+
 static void __init trimslice_init(void)
 {
-	int ret;
-
-	ret = tegra_pcie_init(true, true);
-	if (ret)
-		pr_err("tegra_pci_init() failed: %d\n", ret);
+	tegra_pcie_device.dev.platform_data = &trimslice_pcie_pdata;
+	platform_device_register(&tegra_pcie_device);
 }
 #endif
 
arch/arm/mach-tegra/board-harmony-pcie.c +21 -17
index e8c3fda..8373271 100644
@@ -22,12 +22,14 @@
 
 #include <asm/mach-types.h>
 
+#include <mach/pci-tegra.h>
+
 #include "board.h"
+#include "devices.h"
 #include "board-harmony.h"
 
 #ifdef CONFIG_TEGRA_PCI
-
-int __init harmony_pcie_init(void)
+static int harmony_pcie_board_init(struct platform_device *pdev)
 {
 	struct regulator *regulator = NULL;
 	int err;
@@ -44,30 +46,32 @@ int __init harmony_pcie_init(void)
 
 	regulator_enable(regulator);
 
-	err = tegra_pcie_init(true, true);
-	if (err)
-		goto err_pcie;
-
 	return 0;
 
-err_pcie:
-	regulator_disable(regulator);
-	regulator_put(regulator);
 err_reg:
 	gpio_free(TEGRA_GPIO_EN_VDD_1V05_GPIO);
 
 	return err;
 }
 
-static int __init harmony_pcie_initcall(void)
+static struct tegra_pcie_pdata harmony_pcie_pdata = {
+	.init = harmony_pcie_board_init,
+	.enable_ports = {
+		[0] = true,
+		[1] = true,
+	},
+};
+
+int __init harmony_pcie_init(void)
 {
-	if (!machine_is_harmony())
-		return 0;
+	tegra_pcie_device.dev.platform_data = &harmony_pcie_pdata;
+	platform_device_register(&tegra_pcie_device);
 
-	return harmony_pcie_init();
+	return 0;
+}
+#else
+int __init harmony_pcie_init(void)
+{
+	return 0;
 }
-
-/* PCI should be initialized after I2C, mfd and regulators */
-subsys_initcall_sync(harmony_pcie_initcall);
-
 #endif
arch/arm/mach-tegra/board-harmony.c +1 -0
index e5f3352..063c7d5 100644
@@ -204,6 +204,7 @@ static void __init tegra_harmony_init(void)
 	pwm_add_table(harmony_pwm_lookup, ARRAY_SIZE(harmony_pwm_lookup));
 	harmony_i2c_init();
 	harmony_regulator_init();
+	harmony_pcie_init();
 }
 
 MACHINE_START(HARMONY, "harmony")
arch/arm/mach-tegra/board-harmony.h +1 -0
index 139d96c..afa68e2 100644
@@ -37,5 +37,6 @@
 
 void harmony_pinmux_init(void);
 int harmony_regulator_init(void);
+int harmony_pcie_init(void);
 
 #endif
arch/arm/mach-tegra/board-trimslice.c +13 -5
index 776aa95..30246d2 100644
@@ -34,6 +34,7 @@
 #include <asm/setup.h>
 
 #include <mach/iomap.h>
+#include <mach/pci-tegra.h>
 #include <mach/sdhci.h>
 
 #include "board.h"
@@ -145,14 +146,20 @@ static __initdata struct tegra_clk_init_table trimslice_clk_init_table[] = {
 	{ NULL,		NULL,		0,		0},
 };
 
-static int __init tegra_trimslice_pci_init(void)
+static struct tegra_pcie_pdata trimslice_pcie_pdata = {
+	.enable_ports = {
+		[0] = true,
+		[1] = true,
+	},
+};
+
+static int __init trimslice_pci_init(void)
 {
-	if (!machine_is_trimslice())
-		return 0;
+	tegra_pcie_device.dev.platform_data = &trimslice_pcie_pdata;
+	platform_device_register(&tegra_pcie_device);
 
-	return tegra_pcie_init(true, true);
+	return 0;
 }
-subsys_initcall(tegra_trimslice_pci_init);
 
 static void __init tegra_trimslice_init(void)
 {
@@ -167,6 +174,7 @@ static void __init tegra_trimslice_init(void)
 
 	trimslice_i2c_init();
 	trimslice_usb_init();
+	trimslice_pci_init();
 }
 
 MACHINE_START(TRIMSLICE, "trimslice")
arch/arm/mach-tegra/board.h +1 -1
index f88e514..3a2a7e9 100644
@@ -30,7 +30,6 @@ void __init tegra30_init_early(void);
 void __init tegra_map_common_io(void);
 void __init tegra_init_irq(void);
 void __init tegra_dt_init_irq(void);
-int __init tegra_pcie_init(bool init_port0, bool init_port1);
 
 void tegra_init_late(void);
 
@@ -56,4 +55,5 @@ static inline int harmony_pcie_init(void) { return 0; }
 void __init tegra_paz00_wifikill_init(void);
 
 extern struct sys_timer tegra_timer;
+
 #endif
arch/arm/mach-tegra/devices.c +25 -0
index 4529561..de4aef9 100644
@@ -735,3 +735,28 @@ struct platform_device tegra_nand_device = {
 	.num_resources = ARRAY_SIZE(tegra_nand_resources),
 	.resource = tegra_nand_resources,
 };
+
+static struct resource tegra_pcie_resources[] = {
+	[0] = {
+		.start = TEGRA_PCIE_BASE,
+		.end = TEGRA_PCIE_BASE + TEGRA_PCIE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = TEGRA_PCIE_MMIO_BASE,
+		.end = TEGRA_PCIE_MMIO_BASE + TEGRA_PCIE_MMIO_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[2] = {
+		.start = INT_PCIE_INTR,
+		.end = INT_PCIE_INTR,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device tegra_pcie_device = {
+	.name = "tegra-pcie",
+	.id = -1,
+	.resource = tegra_pcie_resources,
+	.num_resources = ARRAY_SIZE(tegra_pcie_resources),
+};
arch/arm/mach-tegra/devices.h +1 -0
index f054d10..b2caed4 100644
@@ -57,5 +57,6 @@ extern struct platform_device tegra_i2s_device1;
 extern struct platform_device tegra_i2s_device2;
 extern struct platform_device tegra_das_device;
 extern struct platform_device tegra_pwm_device;
+extern struct platform_device tegra_pcie_device;
 
 #endif
arch/arm/mach-tegra/include/mach/iomap.h +6 -0
index 3e80f3f..aee9d27 100644
@@ -248,6 +248,12 @@
 #define TEGRA_CSITE_BASE		0x70040000
 #define TEGRA_CSITE_SIZE		SZ_256K
 
+#define TEGRA_PCIE_BASE			0x80000000
+#define TEGRA_PCIE_SIZE			SZ_4M
+
+#define TEGRA_PCIE_MMIO_BASE		0x80400000
+#define TEGRA_PCIE_MMIO_SIZE		SZ_64K
+
 #define TEGRA_USB_BASE			0xC5000000
 #define TEGRA_USB_SIZE			SZ_16K
 
arch/arm/mach-tegra/include/mach/pci-tegra.h new file +29 -0
new file mode 100644
index 0000000..348a68a
@@ -0,0 +1,29 @@
+/*
+ * arch/arm/mach-tegra/include/mach/tegra-pcie.h
+ *
+ * Copyright (C) 2012 Avionic Design GmbH
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MACH_TEGRA_PCIE_H
+#define __MACH_TEGRA_PCIE_H
+
+#include <linux/platform_device.h>
+
+#define TEGRA_PCIE_MAX_PORTS 2
+
+struct tegra_pcie_pdata {
+	int (*init)(struct platform_device *pdev);
+	int (*exit)(struct platform_device *pdev);
+	bool enable_ports[TEGRA_PCIE_MAX_PORTS];
+};
+
+#endif
arch/arm/mach-tegra/pcie.c +311 -203

889 lines not on this page · raw message

Signature · 1 line
1.7.10.4
#6 lore raw

PATCH v2 5/10 ARM: tegra: Rewrite PCIe support as a driver

Quoted 14 lines · Thierry Reding

This commit adds a platform device driver for the PCIe controller on Tegra SOCs. Current users of the old code (TrimSlice and Harmony) are converted and now initialize and register a corresponding platform device.

arch/arm/mach-tegra/devices.c +7 -0
 
+static struct resource tegra_pcie_resources[] = {
+	[0] = {
+		.start = TEGRA_PCIE_BASE,
+		.end = TEGRA_PCIE_BASE + TEGRA_PCIE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {

arch/arm/mach-tegra/devices.c struct platform_device tegra_nand_device = { · line 755

Quoted 10 lines
arch/arm/mach-tegra/devices.c +10 -0
+		.start = TEGRA_PCIE_MMIO_BASE,
+		.end = TEGRA_PCIE_MMIO_BASE + TEGRA_PCIE_MMIO_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[2] = {
+		.start = INT_PCIE_INTR,
+		.end = INT_PCIE_INTR,
+		.flags = IORESOURCE_IRQ,
+	},
+};

I'm not sure those resources either cover all the necessary regions, nor are as fine-grained as they should be ...

In particular, in pcie.c, I see separate afi_writel() and pads_writel() implying those are separate regions.

Also, I see the following hard-code specific addresses, and are still used by the driver after conversion:

Quoted 8 lines
#define MEM_BASE_0              (TEGRA_PCIE_BASE + SZ_256M)
#define MEM_SIZE_0              SZ_128M
#define MEM_BASE_1              (MEM_BASE_0 + MEM_SIZE_0)
#define MEM_SIZE_1              SZ_128M
#define PREFETCH_MEM_BASE_0     (MEM_BASE_1 + MEM_SIZE_1)
#define PREFETCH_MEM_SIZE_0     SZ_128M
#define PREFETCH_MEM_BASE_1     (PREFETCH_MEM_BASE_0 + PREFETCH_MEM_SIZE_0)
#define PREFETCH_MEM_SIZE_1     SZ_128M

Also, there's a comment describing the register layout in terms of a number of separate regions:

Quoted 7 lines

/*
* Tegra2 defines 1GB in the AXI address map for PCIe.
*
* That address space is split into different regions, with sizes and
* offsets as follows:
*
* 0x80000000 - 0x80003fff - PCI controller registers

Quoted 8 lines

* 0x80004000 - 0x80103fff - PCI configuration space
* 0x80104000 - 0x80203fff - PCI extended configuration space
* 0x80203fff - 0x803fffff - unused
* 0x80400000 - 0x8040ffff - downstream IO
* 0x80410000 - 0x8fffffff - unused
* 0x90000000 - 0x9fffffff - non-prefetchable memory
* 0xa0000000 - 0xbfffffff - prefetchable memory
*/

(the latter 2 regions at least being also split in half for each of the 2 host ports)

Shouldn't each of these regions be a separate entry in the platform device resources.

This perhaps isn't that relevant for Tegra20 alone, but Tegra30 supports 3 host ports instead of 2 (hence I presume alters the internal layout of the 1G chunk of physical memory space allocated to PCIe), and moves the PCIe area from 2G..3G to 0G..1G (so invalidates the hard-coded *_MEM_BASE_* above).

That said, I'm not sure whether Tegra20's and Tegra30's PCIe controllers are similar enough to make a shared driver worthwhile/possible. (Although our downstream Android driver appears to handle both with a very small number of ifdefs). If they are similar, then I think my comments above should be addressed. If they are not similar, then I think you can just have a single 1G memory region in the resources, and split it up internally, rather than needing separate resources for different parts of the address space.

While we can easily fix this kind of driver internals so this doesn't seem like a big deal, this kind of change would impact the device tree binding, so it seems that we need to sort it out before DT conversion.

#7 lore raw

PATCH v2 5/10 ARM: tegra: Rewrite PCIe support as a driver

Quoted 63 lines · Stephen Warren
Quoted 14 lines · Thierry Reding

This commit adds a platform device driver for the PCIe controller on Tegra SOCs. Current users of the old code (TrimSlice and Harmony) are converted and now initialize and register a corresponding platform device.

arch/arm/mach-tegra/devices.c +7 -0
 
+static struct resource tegra_pcie_resources[] = {
+	[0] = {
+		.start = TEGRA_PCIE_BASE,
+		.end = TEGRA_PCIE_BASE + TEGRA_PCIE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {

arch/arm/mach-tegra/devices.c struct platform_device tegra_nand_device = { · line 755

Quoted 10 lines
arch/arm/mach-tegra/devices.c +10 -0
+		.start = TEGRA_PCIE_MMIO_BASE,
+		.end = TEGRA_PCIE_MMIO_BASE + TEGRA_PCIE_MMIO_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[2] = {
+		.start = INT_PCIE_INTR,
+		.end = INT_PCIE_INTR,
+		.flags = IORESOURCE_IRQ,
+	},
+};

I'm not sure those resources either cover all the necessary regions, nor are as fine-grained as they should be ...

In particular, in pcie.c, I see separate afi_writel() and pads_writel() implying those are separate regions.

Also, I see the following hard-code specific addresses, and are still used by the driver after conversion:

Quoted 8 lines
#define MEM_BASE_0              (TEGRA_PCIE_BASE + SZ_256M)
#define MEM_SIZE_0              SZ_128M
#define MEM_BASE_1              (MEM_BASE_0 + MEM_SIZE_0)
#define MEM_SIZE_1              SZ_128M
#define PREFETCH_MEM_BASE_0     (MEM_BASE_1 + MEM_SIZE_1)
#define PREFETCH_MEM_SIZE_0     SZ_128M
#define PREFETCH_MEM_BASE_1     (PREFETCH_MEM_BASE_0 + PREFETCH_MEM_SIZE_0)
#define PREFETCH_MEM_SIZE_1     SZ_128M

Also, there's a comment describing the register layout in terms of a number of separate regions:

Quoted 7 lines

/*
* Tegra2 defines 1GB in the AXI address map for PCIe.
*
* That address space is split into different regions, with sizes and
* offsets as follows:
*
* 0x80000000 - 0x80003fff - PCI controller registers

Quoted 8 lines

* 0x80004000 - 0x80103fff - PCI configuration space
* 0x80104000 - 0x80203fff - PCI extended configuration space
* 0x80203fff - 0x803fffff - unused
* 0x80400000 - 0x8040ffff - downstream IO
* 0x80410000 - 0x8fffffff - unused
* 0x90000000 - 0x9fffffff - non-prefetchable memory
* 0xa0000000 - 0xbfffffff - prefetchable memory
*/

Quoted 2 lines

(the latter 2 regions at least being also split in half for each of the 2 host ports)

I was thinking that maybe each port should be represented as a child node, but I'm not sure that's going to work too well because the children of the pci node are supposed to be PCI busses/devices. I'll have to check whether they could just as well be children of the PCIe port nodes.

That way each port could get an own set of register ranges to better describe the actual layout. AFAICT the even partitioning of the non-prefetchable and prefetchable memory regions is arbitrary and it could potentially be useful to make it configurable via the DT.

Quoted 14 lines

Shouldn't each of these regions be a separate entry in the platform device resources.

This perhaps isn't that relevant for Tegra20 alone, but Tegra30 supports 3 host ports instead of 2 (hence I presume alters the internal layout of the 1G chunk of physical memory space allocated to PCIe), and moves the PCIe area from 2G..3G to 0G..1G (so invalidates the hard-coded *_MEM_BASE_* above).

That said, I'm not sure whether Tegra20's and Tegra30's PCIe controllers are similar enough to make a shared driver worthwhile/possible. (Although our downstream Android driver appears to handle both with a very small number of ifdefs).

Quoted 4 lines

If they are similar, then I think my comments above should be addressed. If they are not similar, then I think you can just have a single 1G memory region in the resources, and split it up internally, rather than needing separate resources for different parts of the address space.

Unfortunately the PCIe controller is very badly documented in the TRM, so this information is hard to locate (I guess the best source is one of the downstream drivers).

Last time I looked they seemed to be simple enough to handle the differences using OF compatible matches. I believe apart from the PCIe area changes there were some differences in how the MSI were setup.

Quoted 3 lines

While we can easily fix this kind of driver internals so this doesn't seem like a big deal, this kind of change would impact the device tree binding, so it seems that we need to sort it out before DT conversion.

Yes, we should at least try to get it right from the start.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120612/bc94282d/attachment-0001.sig>

#8 lore raw

PATCH v2 5/10 ARM: tegra: Rewrite PCIe support as a driver

Quoted 3 lines · Thierry Reding

AFAICT the even partitioning of the non-prefetchable and prefetchable memory regions is arbitrary and it could potentially be useful to make it configurable via the DT.

So it turns out that this isn't true. But apart from the comments in the driver I couldn't find any reference to how the prefetch and non-prefetch ranges are partitioned. Judging by the code for Tegra2 this is evenly partitioned among ports 0 and 1 but it would be interesting to know this is done on Tegra3. Is there any way you can find out?

It'd also be nice if some better documentation for the PCIe controller could be made available. The Tegra2 TRM doesn't contain any of the AFI or PADS registers and while the Tegra3 TRM documents more registers, their offsets are completely missing.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120612/0a21f4a7/attachment.sig>

#9 lore raw

PATCH v2 5/10 ARM: tegra: Rewrite PCIe support as a driver

Quoted 12 lines · Thierry Reding
Quoted 3 lines · Thierry Reding

AFAICT the even partitioning of the non-prefetchable and prefetchable memory regions is arbitrary and it could potentially be useful to make it configurable via the DT.

So it turns out that this isn't true. But apart from the comments in the driver I couldn't find any reference to how the prefetch and non-prefetch ranges are partitioned. Judging by the code for Tegra2 this is evenly partitioned among ports 0 and 1 but it would be interesting to know this is done on Tegra3. Is there any way you can find out?

Quoted 4 lines

It'd also be nice if some better documentation for the PCIe controller could be made available. The Tegra2 TRM doesn't contain any of the AFI or PADS registers and while the Tegra3 TRM documents more registers, their offsets are completely missing.

I've filed a bug to request better documentation.

Looking at our downstream driver, the quoted comment below implies that the address space layout is pretty arbitrary and programmable at least for Tegra30. The code in function tegra_pcie_setup_translations() appears to support this (and is executed for both Tegra20 and Tegra30, even though the comment for Tegra20 doesn't mention any programmability).

Tegra20:

Quoted 7 lines

/*
* Tegra2 defines 1GB in the AXI address map for PCIe.
*
* That address space is split into different regions, with sizes and
* offsets as follows:
*
* 0x80000000 - 0x80003fff - PCI controller registers

Quoted 8 lines

* 0x80004000 - 0x80103fff - PCI configuration space
* 0x80104000 - 0x80203fff - PCI extended configuration space
* 0x80203fff - 0x803fffff - unused
* 0x80400000 - 0x8040ffff - downstream IO
* 0x80410000 - 0x8fffffff - unused
* 0x90000000 - 0x9fffffff - non-prefetchable memory
* 0xa0000000 - 0xbfffffff - prefetchable memory
*/

(I guess by "is split", it means the driver sets it up that way, not that the HW is fixed that way)

Tegra30:

Quoted 21 lines

/*
* AXI address map for the PCIe aperture , defines 1GB in the AXI
* address map for PCIe.
*

 *  That address space is split into different regions, with sizes and
 *  offsets as follows. Exepct for the Register space, SW is free to slice the
 *  regions as it chooces.
 *
 *  The split below seems to work fine for now.
 *
 *  0x0000_0000 to 0x00ff_ffff - Register space          16MB.
 *  0x0100_0000 to 0x01ff_ffff - Config space            16MB.
 *  0x0200_0000 to 0x02ff_ffff - Extended config space   16MB.
 *  0x0300_0000 to 0x03ff_ffff - Downstream IO space
 *   ... Will be filled with other BARS like MSI/upstream IO etc.
 *  0x1000_0000 to 0x1fff_ffff - non-prefetchable memory aperture
 *  0x2000_0000 to 0x3fff_ffff - Prefetchable memory aperture
 *
 *  Config and Extended config sizes are choosen to support
 *  maximum of 256 devices,
 *  which is good enough for all the current use cases.
Quoted 2 lines

*
*/

From
http://nv-tegra.nvidia.com/gitweb/?p=linux-2.6.git;a=blob;f=arch/arm/mach-tegra/pcie.c;h=b98d4892b5ee46120a9777a969e820a0b5cbb68a;hb=android-tegra-nv-3.1

#10 lore raw

PATCH v2 5/10 ARM: tegra: Rewrite PCIe support as a driver

Quoted 74 lines · Stephen Warren
Quoted 12 lines · Thierry Reding
Quoted 3 lines · Thierry Reding

AFAICT the even partitioning of the non-prefetchable and prefetchable memory regions is arbitrary and it could potentially be useful to make it configurable via the DT.

So it turns out that this isn't true. But apart from the comments in the driver I couldn't find any reference to how the prefetch and non-prefetch ranges are partitioned. Judging by the code for Tegra2 this is evenly partitioned among ports 0 and 1 but it would be interesting to know this is done on Tegra3. Is there any way you can find out?

Quoted 4 lines

It'd also be nice if some better documentation for the PCIe controller could be made available. The Tegra2 TRM doesn't contain any of the AFI or PADS registers and while the Tegra3 TRM documents more registers, their offsets are completely missing.

I've filed a bug to request better documentation.

Looking at our downstream driver, the quoted comment below implies that the address space layout is pretty arbitrary and programmable at least for Tegra30. The code in function tegra_pcie_setup_translations() appears to support this (and is executed for both Tegra20 and Tegra30, even though the comment for Tegra20 doesn't mention any programmability).

Tegra20:

Quoted 7 lines

/*
* Tegra2 defines 1GB in the AXI address map for PCIe.
*
* That address space is split into different regions, with sizes and
* offsets as follows:
*
* 0x80000000 - 0x80003fff - PCI controller registers

Quoted 8 lines

* 0x80004000 - 0x80103fff - PCI configuration space
* 0x80104000 - 0x80203fff - PCI extended configuration space
* 0x80203fff - 0x803fffff - unused
* 0x80400000 - 0x8040ffff - downstream IO
* 0x80410000 - 0x8fffffff - unused
* 0x90000000 - 0x9fffffff - non-prefetchable memory
* 0xa0000000 - 0xbfffffff - prefetchable memory
*/

(I guess by "is split", it means the driver sets it up that way, not that the HW is fixed that way)

Tegra30:

Quoted 21 lines

/*
* AXI address map for the PCIe aperture , defines 1GB in the AXI
* address map for PCIe.
*

 *  That address space is split into different regions, with sizes and
 *  offsets as follows. Exepct for the Register space, SW is free to slice the
 *  regions as it chooces.
 *
 *  The split below seems to work fine for now.
 *
 *  0x0000_0000 to 0x00ff_ffff - Register space          16MB.
 *  0x0100_0000 to 0x01ff_ffff - Config space            16MB.
 *  0x0200_0000 to 0x02ff_ffff - Extended config space   16MB.
 *  0x0300_0000 to 0x03ff_ffff - Downstream IO space
 *   ... Will be filled with other BARS like MSI/upstream IO etc.
 *  0x1000_0000 to 0x1fff_ffff - non-prefetchable memory aperture
 *  0x2000_0000 to 0x3fff_ffff - Prefetchable memory aperture
 *
 *  Config and Extended config sizes are choosen to support
 *  maximum of 256 devices,
 *  which is good enough for all the current use cases.
Quoted 2 lines

*
*/

Quoted 2 lines

From
http://nv-tegra.nvidia.com/gitweb/?p=linux-2.6.git;a=blob;f=arch/arm/mach-tegra/pcie.c;h=b98d4892b5ee46120a9777a969e820a0b5cbb68a;hb=android-tegra-nv-3.1

While it is apparently true that each region can be split arbitrarily this doesn't seem to be true for the partitioning of each region between the individual ports.

For instance, while non-prefetchable memory could possibly be mapped either to 0x90000000 or to 0xa0000000 with an arbitrary size, the subregion that is assigned to port 0 or 1 seems to be fixed. Judging by the code this currently seems to be evenly distributed, but it's not so clear how this behaves when port 1 for example is disabled, or how it is distributed on Tegra30 with all three ports enabled (split into 3 equally-sized partitions?).

While the upstream driver currently still initializes the I/O and memory resources for each port (splitting them into equally-sized partitions), the latest downstream driver no longer seems to do so, but instead just initializes a global resource for each resource type (tegra_pcie_preinit()).

I hope the improved documentation that you already requested will shed some light on this.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120613/7c3d998c/attachment.sig>

#11 lore raw

PATCH v2 5/10 ARM: tegra: Rewrite PCIe support as a driver

In reply to Thierry Reding
Quoted 6 lines · Thierry Reding

This commit adds a platform device driver for the PCIe controller on Tegra SOCs. Current users of the old code (TrimSlice and Harmony) are converted and now initialize and register a corresponding platform device.

arch/arm/mach-tegra/pcie.c +0 -1
-static int tegra_pcie_clocks_get(void)

arch/arm/mach-tegra/pcie.c static int tegra_pcie_enable_controller(void) · line 712

Quoted 10 lines
arch/arm/mach-tegra/pcie.c +4 -3
+static int tegra_pcie_clocks_get(struct tegra_pcie_info *pcie)
 {
 	int err;
 
-	tegra_pcie.pex_clk = clk_get(NULL, "pex");
-	if (IS_ERR(tegra_pcie.pex_clk))
-		return PTR_ERR(tegra_pcie.pex_clk);
+	pcie->pex_clk = clk_get(NULL, "pex");
+	if (IS_ERR(pcie->pex_clk))
+		return PTR_ERR(pcie->pex_clk);

While we're changing this, can we convert this to devm_clk_get(), and ...

Quoted 5 lines
arch/arm/mach-tegra/pcie.c +2 -3
-	tegra_pcie.regs = ioremap_nocache(TEGRA_PCIE_BASE, PCIE_IOMAP_SZ);
-	if (tegra_pcie.regs == NULL) {
-		pr_err("PCIE: Failed to map PCI/AFI registers\n");
+	regs = request_mem_region(regs->start, resource_size(regs), "PCI/AFI");
+	if (regs == NULL) {

arch/arm/mach-tegra/pcie.c static int tegra_pcie_enable_controller(void) · line 790

Quoted 10 lines
arch/arm/mach-tegra/pcie.c +7 -0
+		dev_err(&pdev->dev, "failed to request PCI/AFI region: %d\n", err);
+		goto err_req_reg;
+	}
+
+	pcie->regs = ioremap_nocache(regs->start, resource_size(regs));
+	if (pcie->regs == NULL) {
+		dev_err(&pdev->dev, "failed to map PCI/AFI registers\n");
 		err = -ENOMEM;
 		goto err_map_reg;
 	}

... that to devm_request_and_ioremap(). That would allow a bunch of the cleanup code to be deleted rather than just modified.

#12 lore raw

PATCH v2 5/10 ARM: tegra: Rewrite PCIe support as a driver

Quoted 11 lines · Stephen Warren
Quoted 10 lines · Thierry Reding

This commit adds a platform device driver for the PCIe controller on Tegra SOCs. Current users of the old code (TrimSlice and Harmony) are converted and now initialize and register a corresponding platform device.

arch/arm/mach-tegra/pcie.c +1 -1
-static int tegra_pcie_clocks_get(void)
+static int tegra_pcie_clocks_get(struct tegra_pcie_info *pcie)
 {
 	int err;
Quoted 8 lines

arch/arm/mach-tegra/pcie.c static int tegra_pcie_enable_controller(void) · line 712

Quoted 6 lines
arch/arm/mach-tegra/pcie.c +3 -3
-	tegra_pcie.pex_clk = clk_get(NULL, "pex");
-	if (IS_ERR(tegra_pcie.pex_clk))
-		return PTR_ERR(tegra_pcie.pex_clk);
+	pcie->pex_clk = clk_get(NULL, "pex");
+	if (IS_ERR(pcie->pex_clk))
+		return PTR_ERR(pcie->pex_clk);

While we're changing this, can we convert this to devm_clk_get(), and ...

Will do.

Quoted 10 lines
Quoted 10 lines
arch/arm/mach-tegra/pcie.c +7 -3
-	tegra_pcie.regs = ioremap_nocache(TEGRA_PCIE_BASE, PCIE_IOMAP_SZ);
-	if (tegra_pcie.regs == NULL) {
-		pr_err("PCIE: Failed to map PCI/AFI registers\n");
+	regs = request_mem_region(regs->start, resource_size(regs), "PCI/AFI");
+	if (regs == NULL) {
+		dev_err(&pdev->dev, "failed to request PCI/AFI region: %d\n", err);
+		goto err_req_reg;
+	}
+
+	pcie->regs = ioremap_nocache(regs->start, resource_size(regs));
Quoted 8 lines

arch/arm/mach-tegra/pcie.c static int tegra_pcie_enable_controller(void) · line 790

Quoted 5 lines
arch/arm/mach-tegra/pcie.c +2 -0
+	if (pcie->regs == NULL) {
+		dev_err(&pdev->dev, "failed to map PCI/AFI registers\n");
 		err = -ENOMEM;
 		goto err_map_reg;
 	}

... that to devm_request_and_ioremap(). That would allow a bunch of the cleanup code to be deleted rather than just modified.

Yes, I'll fix that up as well.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120612/4cfb6a75/attachment.sig>

#13 lore raw

PATCH v2 6/10 ARM: tegra: pcie: Add MSI support

In reply to Thierry Reding

This commit adds support for message signaled interrupts to the Tegra PCIe controller. Based on code by Krishna Kishore <[email protected]>.

---
Changes in v2:
- improve compile coverage by using the IS_ENABLED() macro
- move MSI-related fields to a separate structure
- free pages used for the AFI/FPCI region
- properly remove IRQ domain on module removal
- disable MSI interrupt on module removal
- use linear IRQ domain

---
 arch/arm/mach-tegra/Kconfig             |    1 +
 arch/arm/mach-tegra/devices.c           |    7 +
 arch/arm/mach-tegra/include/mach/irqs.h |    5 +-
 arch/arm/mach-tegra/pcie.c              |  268 +++++++++++++++++++++++++++++++
 4 files changed, 280 insertions(+), 1 deletion(-)
arch/arm/mach-tegra/Kconfig +1 -0
index cf129d6..4dd6945 100644
@@ -48,6 +48,7 @@ config ARCH_TEGRA_3x_SOC
 config TEGRA_PCI
 	bool "PCI Express support"
 	depends on ARCH_TEGRA_2x_SOC
+	select ARCH_SUPPORTS_MSI
 	select PCI
 
 config TEGRA_AHB
arch/arm/mach-tegra/devices.c +7 -0
index de4aef9..03da0f7 100644
@@ -752,6 +752,13 @@ static struct resource tegra_pcie_resources[] = {
 		.end = INT_PCIE_INTR,
 		.flags = IORESOURCE_IRQ,
 	},
+#ifdef CONFIG_PCI_MSI
+	[3] = {
+		.start = INT_PCIE_MSI,
+		.end = INT_PCIE_MSI,
+		.flags = IORESOURCE_IRQ,
+	},
+#endif
 };
 
 struct platform_device tegra_pcie_device = {
arch/arm/mach-tegra/include/mach/irqs.h +4 -1
index 0a0dcac..a282524 100644
@@ -172,7 +172,10 @@
 /* Tegra30 has 8 banks of 32 GPIOs */
 #define INT_GPIO_NR			(32 * 8)
 
-#define TEGRA_NR_IRQS			(INT_GPIO_BASE + INT_GPIO_NR)
+#define INT_PCI_MSI_BASE		(INT_GPIO_BASE + INT_GPIO_NR)
+#define INT_PCI_MSI_NR			(32 * 8)
+
+#define TEGRA_NR_IRQS			(INT_PCI_MSI_BASE + INT_PCI_MSI_NR)
 
 #define INT_BOARD_BASE			TEGRA_NR_IRQS
 #define NR_BOARD_IRQS			128
arch/arm/mach-tegra/pcie.c +268 -0

315 lines not on this page · raw message

Signature · 1 line
1.7.10.4
#14 lore raw

PATCH v2 6/10 ARM: tegra: pcie: Add MSI support

Quoted 6 lines · Thierry Reding

This commit adds support for message signaled interrupts to the Tegra PCIe controller. Based on code by Krishna Kishore <[email protected]>.

arch/arm/mach-tegra/pcie.c +1 -0
 
+static irqreturn_t tegra_pcie_msi_irq(int irq, void *data)

...

arch/arm/mach-tegra/pcie.c static void __devinit tegra_pcie_add_port(struct tegra_pcie_info *pcie, · line 1018

Quoted 4 lines
arch/arm/mach-tegra/pcie.c +4 -0
+			irq = irq_find_mapping(pcie->msi->domain, index);
+			if (irq) {
+				if (test_bit(index, pcie->msi->used))
+					generic_handle_irq(irq);

This invokes the handler first ...

...

arch/arm/mach-tegra/pcie.c static void __devinit tegra_pcie_add_port(struct tegra_pcie_info *pcie, · line 1032

Quoted 4 lines
arch/arm/mach-tegra/pcie.c +4 -0
+			/* clear the interrupt */
+			afi_writel(pcie, 1 << offset, AFI_MSI_VEC0 + i * 4);
+			/* see if there's any more pending in this vector */
+			reg = afi_readl(pcie, AFI_MSI_VEC0 + i * 4);

... then clears the interrupt status in the PCIe controller. Won't that lose interrupts if one is raised between when the handler clears the root-cause, and when this code clears the received interrupt status?

Quoted 1 line

+static int tegra_pcie_disable_msi(struct platform_device *pdev)

Should this free pcie->msi->pages?

Why allocate pcie->msi separately; why not include the fields directly into struct tegra_pcie_info *pcie?

#15 lore raw

PATCH v2 6/10 ARM: tegra: pcie: Add MSI support

Quoted 16 lines · Stephen Warren
Quoted 6 lines · Thierry Reding

This commit adds support for message signaled interrupts to the Tegra PCIe controller. Based on code by Krishna Kishore <[email protected]>.

arch/arm/mach-tegra/pcie.c +1 -0
 
+static irqreturn_t tegra_pcie_msi_irq(int irq, void *data)

...

arch/arm/mach-tegra/pcie.c static void __devinit tegra_pcie_add_port(struct tegra_pcie_info *pcie, · line 1018

Quoted 4 lines
arch/arm/mach-tegra/pcie.c +4 -0
+			irq = irq_find_mapping(pcie->msi->domain, index);
+			if (irq) {
+				if (test_bit(index, pcie->msi->used))
+					generic_handle_irq(irq);

This invokes the handler first ...

...

Quoted 8 lines

arch/arm/mach-tegra/pcie.c static void __devinit tegra_pcie_add_port(struct tegra_pcie_info *pcie, · line 1032

Quoted 4 lines
arch/arm/mach-tegra/pcie.c +4 -0
+			/* clear the interrupt */
+			afi_writel(pcie, 1 << offset, AFI_MSI_VEC0 + i * 4);
+			/* see if there's any more pending in this vector */
+			reg = afi_readl(pcie, AFI_MSI_VEC0 + i * 4);

... then clears the interrupt status in the PCIe controller. Won't that lose interrupts if one is raised between when the handler clears the root-cause, and when this code clears the received interrupt status?

It certainly doesn't follow the conventional way of clearing the interrupt first. I carried this from the original MSI patch, but I'll move the interrupt clearing up and retest.

Quoted 3 lines
Quoted 1 line

+static int tegra_pcie_disable_msi(struct platform_device *pdev)

Should this free pcie->msi->pages?

Yes it should. I actually mention making that change in the changelog but in fact didn't.

Quoted 2 lines

Why allocate pcie->msi separately; why not include the fields directly into struct tegra_pcie_info *pcie?

For one I find this easier to read. If this wasn't a separate structure, each of the individual fields would get an msi_ prefix anyway so there isn't much to be gained from keeping them directly in tegra_pcie_info.

Second, and more importantly, this will keep the size of struct tegra_pcie_info smaller if PCI_MSI is not selected because there is just one unused pointer instead of five unused fields.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120612/ca927330/attachment.sig>

#16 lore raw

PATCH v2 6/10 ARM: tegra: pcie: Add MSI support

Quoted 5 lines · Thierry Reding
Quoted 4 lines · Stephen Warren
Quoted 3 lines · Thierry Reding

This commit adds support for message signaled interrupts to the Tegra PCIe controller. Based on code by Krishna Kishore <[email protected]>.

...

Quoted 2 lines
Quoted 2 lines

Why allocate pcie->msi separately; why not include the fields directly into struct tegra_pcie_info *pcie?

...

Quoted 3 lines

Second, and more importantly, this will keep the size of struct tegra_pcie_info smaller if PCI_MSI is not selected because there is just one unused pointer instead of five unused fields.

Well, you can always ifdef out the structure fields too, right?

#17 lore raw

PATCH v2 6/10 ARM: tegra: pcie: Add MSI support

Quoted 7 lines · Stephen Warren
Quoted 5 lines · Thierry Reding
Quoted 4 lines · Stephen Warren
Quoted 3 lines · Thierry Reding

This commit adds support for message signaled interrupts to the Tegra PCIe controller. Based on code by Krishna Kishore <[email protected]>.

...

Quoted 8 lines
Quoted 2 lines
Quoted 2 lines

Why allocate pcie->msi separately; why not include the fields directly into struct tegra_pcie_info *pcie?

...

Quoted 3 lines

Second, and more importantly, this will keep the size of struct tegra_pcie_info smaller if PCI_MSI is not selected because there is just one unused pointer instead of five unused fields.

Well, you can always ifdef out the structure fields too, right?

Not if you use the IS_ENABLED() macro. It's supposed to increase compile coverage for a trade-off in memory usage because like in this case some fields may be unused.

I find this very convenient because it prevents situations where build errors don't show up until somebody uses the code in an unusual configuration. For developers this makes it really easy because they don't have to test every possible permutation of configuration options.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120612/2e8846d7/attachment.sig>

#18 lore raw

PATCH v2 6/10 ARM: tegra: pcie: Add MSI support

In reply to Thierry Reding
Quoted 2 lines · Thierry Reding
Quoted 1 line · Stephen Warren

On 06/11/2012 09:05 AM, Thierry Reding wrote:

[...]

Quoted 6 lines
Quoted 3 lines
Quoted 1 line

+static int tegra_pcie_disable_msi(struct platform_device *pdev)

Should this free pcie->msi->pages?

Yes it should. I actually mention making that change in the changelog but in fact didn't.

This is really moot because the driver cannot be built as a module currently because arch_setup_msi_irq() and arch_teardown_msi_irq() need to be built-in so tegra_pcie_disable_msi() will be called only just before the machine is shut down.

Perhaps this is something that should be addressed? Or is it just not worth the effort?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120612/92722551/attachment.sig>

#19 lore raw

PATCH v2 6/10 ARM: tegra: pcie: Add MSI support

Quoted 12 lines · Thierry Reding
Quoted 2 lines · Thierry Reding
Quoted 1 line · Stephen Warren

On 06/11/2012 09:05 AM, Thierry Reding wrote:

[...]

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

+static int tegra_pcie_disable_msi(struct platform_device *pdev)

Should this free pcie->msi->pages?

Yes it should. I actually mention making that change in the changelog but in fact didn't.

Quoted 7 lines

This is really moot because the driver cannot be built as a module currently because arch_setup_msi_irq() and arch_teardown_msi_irq() need to be built-in so tegra_pcie_disable_msi() will be called only just before the machine is shut down.

Perhaps this is something that should be addressed? Or is it just not worth the effort?

Well, if the driver provides a shutdown/removal path at all, it seems like it should be complete. I assume it's trivial to free those pages?

#20 lore raw

PATCH v2 6/10 ARM: tegra: pcie: Add MSI support

Quoted 18 lines · Stephen Warren
Quoted 17 lines · Thierry Reding
Quoted 2 lines · Thierry Reding
Quoted 1 line · Stephen Warren

On 06/11/2012 09:05 AM, Thierry Reding wrote:

[...]

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

+static int tegra_pcie_disable_msi(struct platform_device *pdev)

Should this free pcie->msi->pages?

Yes it should. I actually mention making that change in the changelog but in fact didn't.

This is really moot because the driver cannot be built as a module currently because arch_setup_msi_irq() and arch_teardown_msi_irq() need to be built-in so tegra_pcie_disable_msi() will be called only just before the machine is shut down.

Quoted 5 lines
Quoted 2 lines

Perhaps this is something that should be addressed? Or is it just not worth the effort?

Well, if the driver provides a shutdown/removal path at all, it seems like it should be complete. I assume it's trivial to free those pages?

Yes, it's trivial and I'll definitely add it. What I was saying is that it doesn't matter really, unless something is done to allow the driver to be built as a module. It is also tedious to test the shutdown/removal for built-in drivers.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120612/7b6113bc/attachment.sig>

#21 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

In reply to Thierry Reding

This commit adds support for instantiating the Tegra PCIe controller from a device tree.

---
Changes in v2:
- increase compile coverage by using the IS_ENABLED() macro
- disable node by default

---
 .../devicetree/bindings/pci/tegra-pcie.txt         |   23 ++++
 arch/arm/boot/dts/tegra20.dtsi                     |    9 ++
 arch/arm/mach-tegra/pcie.c                         |  120 +++++++++++++++++++-
 3 files changed, 149 insertions(+), 3 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pci/tegra-pcie.txt
Documentation/devicetree/bindings/pci/tegra-pcie.txt new file +23 -0
new file mode 100644
index 0000000..10bbc40
@@ -0,0 +1,23 @@
+NVIDIA Tegra PCIe controller
+
+Required properties:
+- compatible: "nvidia,tegra20-pcie"
+- reg: physical base address and length of the controller's registers
+- interrupts: the interrupt outputs of the controller
+
+Optional properties:
+- pex-clk-supply: supply voltage for internal reference clock
+- vdd-supply: power supply for controller (1.05V)
+
+Example:
+
+	pci at 80000000 {
+		compatible = "nvidia,tegra20-pcie",
+		reg = <0x80000000 0x400000   /* PCIe AFI registers */
+		       0x80400000 0x010000>; /* PCI I/O space */
+		interrupts = < 0 98 0x04    /* controller interrupt */
+		               0 99 0x04 >; /* MSI interrupt */
+
+		pex-clk-supply = <&ldo0_reg>;
+		vdd-supply = <&pcie_reg>;
+	};
arch/arm/boot/dts/tegra20.dtsi +9 -0
index fa56519..b212658 100644
@@ -199,6 +199,15 @@
 		#size-cells = <0>;
 	};
 
+	pci {
+		compatible = "nvidia,tegra20-pcie";
+		reg = <0x80000000 0x400000   /* PCIe AFI registers */
+		       0x80400000 0x010000>; /* PCI I/O space */
+		interrupts = < 0 98 0x04    /* controller interrupt */
+		               0 99 0x04 >; /* MSI interrupt */
+		status = "disable";
+	};
+
 	usb at c5000000 {
 		compatible = "nvidia,tegra20-ehci", "usb-ehci";
 		reg = <0xc5000000 0x4000>;
arch/arm/mach-tegra/pcie.c +117 -3

168 lines not on this page · raw message

Signature · 1 line
1.7.10.4
#22 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 4 lines · Thierry Reding

This commit adds support for instantiating the Tegra PCIe controller from a device tree.

+++ b/Documentation/devicetree/bindings/pci/tegra-pcie.txt

Can we please name this nvidia,tegra20-pcie.txt to match the naming of all the other Tegra bindings.

Quoted 3 lines

+Required properties:

+- compatible: "nvidia,tegra20-pcie"
+- reg: physical base address and length of the controller's registers

Since there's more than one range now, that should specify how many entries are required and what they represent.

Quoted 3 lines

+Optional properties:

+- pex-clk-supply: supply voltage for internal reference clock
+- vdd-supply: power supply for controller (1.05V)

Those shouldn't be optional. If the board has no regulator, the board's .dts should provide a fixed always-on regulator that those properties can refer to, so that the driver can always get() those regulators.

Quoted 3 lines
arch/arm/boot/dts/tegra20.dtsi +1 -0
 
+	pci {

...

arch/arm/boot/dts/tegra20.dtsi line 208

Quoted 1 line
arch/arm/boot/dts/tegra20.dtsi +1 -0
+		status = "disable";

That should be "disabled"; sorry for providing a bad example.

arch/arm/mach-tegra/pcie.c static int tegra_pcie_disable_msi(struct platform_device *pdev) · line 1270

Quoted 5 lines
arch/arm/mach-tegra/pcie.c +2 -0
 
+static struct tegra_pcie_pdata *tegra_pcie_parse_dt(struct platform_device *pdev)
 
+	if (of_find_property(node, "vdd-supply", NULL)) {

As mentioned above, that if statement should be removed, since the regulators shouldn't be optional.

arch/arm/mach-tegra/pcie.c static int tegra_pcie_disable_msi(struct platform_device *pdev) · line 1271

Quoted 1 line
arch/arm/mach-tegra/pcie.c +1 -0
+		pcie->vdd_supply = regulator_get(&pdev->dev, "vdd");

Those could be devm_regulator_get(). Then tegra_pcie_remove() wouldn't have to put() them.

arch/arm/mach-tegra/pcie.c static int tegra_pcie_disable_msi(struct platform_device *pdev) · line 1283

Quoted 2 lines
arch/arm/mach-tegra/pcie.c +2 -0
+	for (i = 0; i < TEGRA_PCIE_MAX_PORTS; i++)
+		pdata->enable_ports[i] = true;

Shouldn't the DT indicate which ports are used? I assume there's some reason that the existing driver allows that to be configured, rather than always enabling all ports. At least, enumeration time wasted on non-existent ports springs to mind, and perhaps attempting to enable port 1 when port 0 is x4 and using all the lanes would cause errors in port 0?

#23 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 8 lines · Stephen Warren
Quoted 4 lines · Thierry Reding

This commit adds support for instantiating the Tegra PCIe controller from a device tree.

+++ b/Documentation/devicetree/bindings/pci/tegra-pcie.txt

Can we please name this nvidia,tegra20-pcie.txt to match the naming of all the other Tegra bindings.

Yes, will do.

Quoted 6 lines
Quoted 3 lines

+Required properties:

+- compatible: "nvidia,tegra20-pcie"
+- reg: physical base address and length of the controller's registers

Since there's more than one range now, that should specify how many entries are required and what they represent.

Okay.

Quoted 7 lines
Quoted 3 lines

+Optional properties:

+- pex-clk-supply: supply voltage for internal reference clock
+- vdd-supply: power supply for controller (1.05V)

Those shouldn't be optional. If the board has no regulator, the board's .dts should provide a fixed always-on regulator that those properties can refer to, so that the driver can always get() those regulators.

That'll add more dummy regulators and I don't think sprinkling them across the DTS is going to work very well. Maybe collecting them under a top-level "regulators" node is a good option. If you have a better alternative, I'm all open for it.

Quoted 7 lines
Quoted 3 lines
arch/arm/boot/dts/tegra20.dtsi +1 -0
 
+	pci {

...

arch/arm/boot/dts/tegra20.dtsi line 208

Quoted 1 line
arch/arm/boot/dts/tegra20.dtsi +1 -0
+		status = "disable";

That should be "disabled"; sorry for providing a bad example.

Yes.

Quoted 8 lines

arch/arm/mach-tegra/pcie.c static int tegra_pcie_disable_msi(struct platform_device *pdev) · line 1270

Quoted 5 lines
arch/arm/mach-tegra/pcie.c +2 -0
 
+static struct tegra_pcie_pdata *tegra_pcie_parse_dt(struct platform_device *pdev)
 
+	if (of_find_property(node, "vdd-supply", NULL)) {

As mentioned above, that if statement should be removed, since the regulators shouldn't be optional.

Okay.

Quoted 4 lines

arch/arm/mach-tegra/pcie.c static int tegra_pcie_disable_msi(struct platform_device *pdev) · line 1271

Quoted 1 line
arch/arm/mach-tegra/pcie.c +1 -0
+		pcie->vdd_supply = regulator_get(&pdev->dev, "vdd");

Those could be devm_regulator_get(). Then tegra_pcie_remove() wouldn't have to put() them.

Okay.

Quoted 9 lines

arch/arm/mach-tegra/pcie.c static int tegra_pcie_disable_msi(struct platform_device *pdev) · line 1283

Quoted 2 lines
arch/arm/mach-tegra/pcie.c +2 -0
+	for (i = 0; i < TEGRA_PCIE_MAX_PORTS; i++)
+		pdata->enable_ports[i] = true;

Shouldn't the DT indicate which ports are used? I assume there's some reason that the existing driver allows that to be configured, rather than always enabling all ports. At least, enumeration time wasted on non-existent ports springs to mind, and perhaps attempting to enable port 1 when port 0 is x4 and using all the lanes would cause errors in port 0?

Yes, that's been on my mind as well. I'm not sure about the best binding for this. Perhaps something like:

	pci {
		enable-ports = <0 1 2>;
	};

Would do?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120612/525d5b8b/attachment.sig>

#24 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 76 lines · Thierry Reding
Quoted 8 lines · Stephen Warren
Quoted 4 lines · Thierry Reding

This commit adds support for instantiating the Tegra PCIe controller from a device tree.

+++ b/Documentation/devicetree/bindings/pci/tegra-pcie.txt

Can we please name this nvidia,tegra20-pcie.txt to match the naming of all the other Tegra bindings.

Yes, will do.

Quoted 6 lines
Quoted 3 lines

+Required properties: +- compatible: "nvidia,tegra20-pcie" +-
reg: physical base address and length of the controller's registers

Since there's more than one range now, that should specify how many entries are required and what they represent.

Okay.

Quoted 8 lines
Quoted 3 lines

+Optional properties: +- pex-clk-supply: supply voltage for internal reference clock +- vdd-supply: power supply for controller (1.05V)

Those shouldn't be optional. If the board has no regulator, the board's .dts should provide a fixed always-on regulator that those properties can refer to, so that the driver can always get() those regulators.

That'll add more dummy regulators and I don't think sprinkling them across the DTS is going to work very well. Maybe collecting them under a top-level "regulators" node is a good option. If you have a better alternative, I'm all open for it.

Quoted 8 lines
Quoted 4 lines
arch/arm/boot/dts/tegra20.dtsi +1 -0
 
+	pci {

...

arch/arm/boot/dts/tegra20.dtsi line 208

Quoted 1 line
arch/arm/boot/dts/tegra20.dtsi +1 -0
+		status = "disable";

That should be "disabled"; sorry for providing a bad example.

Yes.

Quoted 10 lines

arch/arm/mach-tegra/pcie.c static int tegra_pcie_disable_msi(struct platform_device *pdev) · line 1270

Quoted 7 lines
arch/arm/mach-tegra/pcie.c +1 -0
 
+static struct tegra_pcie_pdata *tegra_pcie_parse_dt(struct

platform_device *pdev)

arch/arm/mach-tegra/pcie.c +1 -0
+	if (of_find_property(node, "vdd-supply", NULL)) {

As mentioned above, that if statement should be removed, since the regulators shouldn't be optional.

Okay.

Quoted 4 lines

arch/arm/mach-tegra/pcie.c static int tegra_pcie_disable_msi(struct platform_device *pdev) · line 1271

Quoted 1 line
arch/arm/mach-tegra/pcie.c +1 -0
+		pcie->vdd_supply = regulator_get(&pdev->dev, "vdd");

Those could be devm_regulator_get(). Then tegra_pcie_remove() wouldn't have to put() them.

Okay.

Quoted 9 lines
Quoted 2 lines
arch/arm/mach-tegra/pcie.c +1 -0
+	for (i = 0; i < TEGRA_PCIE_MAX_PORTS; i++) +

pdata->enable_ports[i] = true;

Shouldn't the DT indicate which ports are used? I assume there's some reason that the existing driver allows that to be configured, rather than always enabling all ports. At least, enumeration time wasted on non-existent ports springs to mind, and perhaps attempting to enable port 1 when port 0 is x4 and using all the lanes would cause errors in port 0?

Quoted 6 lines

Yes, that's been on my mind as well. I'm not sure about the best binding for this. Perhaps something like:

pci { enable-ports = <0 1 2>; };

Would do?

That seems reasonable, although since the property is presumably something specific to the Tegra PCIe binding, not generic, I think it should be nvidia,enable-ports.

#25 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 80 lines · Stephen Warren
Quoted 79 lines · Thierry Reding
Quoted 8 lines · Stephen Warren
Quoted 4 lines · Thierry Reding

This commit adds support for instantiating the Tegra PCIe controller from a device tree.

+++ b/Documentation/devicetree/bindings/pci/tegra-pcie.txt

Can we please name this nvidia,tegra20-pcie.txt to match the naming of all the other Tegra bindings.

Yes, will do.

Quoted 6 lines
Quoted 3 lines

+Required properties: +- compatible: "nvidia,tegra20-pcie" +-
reg: physical base address and length of the controller's registers

Since there's more than one range now, that should specify how many entries are required and what they represent.

Okay.

Quoted 8 lines
Quoted 3 lines

+Optional properties: +- pex-clk-supply: supply voltage for internal reference clock +- vdd-supply: power supply for controller (1.05V)

Those shouldn't be optional. If the board has no regulator, the board's .dts should provide a fixed always-on regulator that those properties can refer to, so that the driver can always get() those regulators.

That'll add more dummy regulators and I don't think sprinkling them across the DTS is going to work very well. Maybe collecting them under a top-level "regulators" node is a good option. If you have a better alternative, I'm all open for it.

Quoted 8 lines
Quoted 4 lines
arch/arm/boot/dts/tegra20.dtsi +1 -0
 
+	pci {

...

arch/arm/boot/dts/tegra20.dtsi line 208

Quoted 1 line
arch/arm/boot/dts/tegra20.dtsi +1 -0
+		status = "disable";

That should be "disabled"; sorry for providing a bad example.

Yes.

Quoted 10 lines

arch/arm/mach-tegra/pcie.c static int tegra_pcie_disable_msi(struct platform_device *pdev) · line 1270

Quoted 7 lines
arch/arm/mach-tegra/pcie.c +1 -0
 
+static struct tegra_pcie_pdata *tegra_pcie_parse_dt(struct

platform_device *pdev)

arch/arm/mach-tegra/pcie.c +1 -0
+	if (of_find_property(node, "vdd-supply", NULL)) {

As mentioned above, that if statement should be removed, since the regulators shouldn't be optional.

Okay.

Quoted 4 lines

arch/arm/mach-tegra/pcie.c static int tegra_pcie_disable_msi(struct platform_device *pdev) · line 1271

Quoted 1 line
arch/arm/mach-tegra/pcie.c +1 -0
+		pcie->vdd_supply = regulator_get(&pdev->dev, "vdd");

Those could be devm_regulator_get(). Then tegra_pcie_remove() wouldn't have to put() them.

Okay.

Quoted 9 lines
Quoted 2 lines
arch/arm/mach-tegra/pcie.c +1 -0
+	for (i = 0; i < TEGRA_PCIE_MAX_PORTS; i++) +

pdata->enable_ports[i] = true;

Shouldn't the DT indicate which ports are used? I assume there's some reason that the existing driver allows that to be configured, rather than always enabling all ports. At least, enumeration time wasted on non-existent ports springs to mind, and perhaps attempting to enable port 1 when port 0 is x4 and using all the lanes would cause errors in port 0?

Yes, that's been on my mind as well. I'm not sure about the best binding for this. Perhaps something like:

Quoted 7 lines
Quoted 3 lines

pci { enable-ports = <0 1 2>; };

Would do?

That seems reasonable, although since the property is presumably something specific to the Tegra PCIe binding, not generic, I think it should be nvidia,enable-ports.

I came up with the following alternative:

	pci {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000   /* extended configuration space */
		       0x80400000 0x00010000   /* downstream I/O */
		       0x90000000 0x10000000   /* non-prefetchable memory */
		       0xa0000000 0x10000000>; /* prefetchable memory */
		interrupts = <0 98 0x04   /* controller interrupt */
		              0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80104000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells = <1>;
		#size-cells = <1>;

		port at 80000000 {
			reg = <0x80000000 0x00001000>;
			status = "disabled";
		};

		port at 80001000 {
			reg = <0x80001000 0x00001000>;
			status = "disabled";
		};
	};

The "ranges" property can probably be cleaned up a bit, but the most interesting part is the port@ children, which can simply be enabled in board DTS files by setting the status property to "okay". I find that somewhat more intuitive to the variant with an "enable-ports" property.

What do you think of this?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120612/9af0c2bb/attachment-0001.sig>

#26 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 125 lines · Thierry Reding
Quoted 80 lines · Stephen Warren
Quoted 79 lines · Thierry Reding
Quoted 8 lines · Stephen Warren
Quoted 4 lines · Thierry Reding

This commit adds support for instantiating the Tegra PCIe controller from a device tree.

+++ b/Documentation/devicetree/bindings/pci/tegra-pcie.txt

Can we please name this nvidia,tegra20-pcie.txt to match the naming of all the other Tegra bindings.

Yes, will do.

Quoted 6 lines
Quoted 3 lines

+Required properties: +- compatible: "nvidia,tegra20-pcie" +-
reg: physical base address and length of the controller's registers

Since there's more than one range now, that should specify how many entries are required and what they represent.

Okay.

Quoted 8 lines
Quoted 3 lines

+Optional properties: +- pex-clk-supply: supply voltage for internal reference clock +- vdd-supply: power supply for controller (1.05V)

Those shouldn't be optional. If the board has no regulator, the board's .dts should provide a fixed always-on regulator that those properties can refer to, so that the driver can always get() those regulators.

That'll add more dummy regulators and I don't think sprinkling them across the DTS is going to work very well. Maybe collecting them under a top-level "regulators" node is a good option. If you have a better alternative, I'm all open for it.

Quoted 8 lines
Quoted 4 lines
arch/arm/boot/dts/tegra20.dtsi +1 -0
 
+	pci {

...

arch/arm/boot/dts/tegra20.dtsi line 208

Quoted 1 line
arch/arm/boot/dts/tegra20.dtsi +1 -0
+		status = "disable";

That should be "disabled"; sorry for providing a bad example.

Yes.

Quoted 10 lines

arch/arm/mach-tegra/pcie.c static int tegra_pcie_disable_msi(struct platform_device *pdev) · line 1270

Quoted 7 lines
arch/arm/mach-tegra/pcie.c +1 -0
 
+static struct tegra_pcie_pdata *tegra_pcie_parse_dt(struct

platform_device *pdev)

arch/arm/mach-tegra/pcie.c +1 -0
+	if (of_find_property(node, "vdd-supply", NULL)) {

As mentioned above, that if statement should be removed, since the regulators shouldn't be optional.

Okay.

Quoted 4 lines

arch/arm/mach-tegra/pcie.c static int tegra_pcie_disable_msi(struct platform_device *pdev) · line 1271

Quoted 1 line
arch/arm/mach-tegra/pcie.c +1 -0
+		pcie->vdd_supply = regulator_get(&pdev->dev, "vdd");

Those could be devm_regulator_get(). Then tegra_pcie_remove() wouldn't have to put() them.

Okay.

Quoted 9 lines
Quoted 2 lines
arch/arm/mach-tegra/pcie.c +1 -0
+	for (i = 0; i<  TEGRA_PCIE_MAX_PORTS; i++) +

pdata->enable_ports[i] = true;

Shouldn't the DT indicate which ports are used? I assume there's some reason that the existing driver allows that to be configured, rather than always enabling all ports. At least, enumeration time wasted on non-existent ports springs to mind, and perhaps attempting to enable port 1 when port 0 is x4 and using all the lanes would cause errors in port 0?

Yes, that's been on my mind as well. I'm not sure about the best binding for this. Perhaps something like:

Quoted 7 lines
Quoted 3 lines

pci { enable-ports =<0 1 2>; };

Would do?

That seems reasonable, although since the property is presumably something specific to the Tegra PCIe binding, not generic, I think it should be nvidia,enable-ports.

I came up with the following alternative:

	pci {
		compatible = "nvidia,tegra20-pcie";
		reg =<0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000   /* extended configuration space */
		       0x80400000 0x00010000   /* downstream I/O */
		       0x90000000 0x10000000   /* non-prefetchable memory */
		       0xa0000000 0x10000000>; /* prefetchable memory */
		interrupts =<0 98 0x04   /* controller interrupt */
		              0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges =<0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80104000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells =<1>;
		#size-cells =<1>;

		port at 80000000 {
			reg =<0x80000000 0x00001000>;
			status = "disabled";
		};

		port at 80001000 {
			reg =<0x80001000 0x00001000>;
			status = "disabled";
		};
	};
Quoted 6 lines

The "ranges" property can probably be cleaned up a bit, but the most interesting part is the port@ children, which can simply be enabled in board DTS files by setting the status property to "okay". I find that somewhat more intuitive to the variant with an "enable-ports" property.

What do you think of this?

The problem is that children of a PCI-ish bus have specific expectations about the parent address format - the standard 3-address-cell PCI addressing. So making a PCI bus node - even if it is PCIe - with 1 address cell is a problem.

Also, if a given address range is listed in "reg", it should not also be listed in "ranges". A block of addresses is either "claimed" by the parent node (reg property) or passed through to its children (ranges property), but not both. "reg" entries are appropriate for entities that pertain to the overall control of the bus interface itself, while "ranges" entries are for chunks of address space that are overlaid onto child devices.

Quoted 9 lines

Thierry

_______________________________________________
devicetree-discuss mailing list
devicetree-discuss at lists.ozlabs.org
https://lists.ozlabs.org/listinfo/devicetree-discuss

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120612/f97d2ef4/attachment-0001.html>

#27 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 1 line · Mitch Bradley

On 6/12/2012 7:20 AM, Thierry Reding wrote:

...

Quoted 41 lines
Quoted 41 lines

I came up with the following alternative:

	pci {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000   /* extended configuration space */
		       0x80400000 0x00010000   /* downstream I/O */
		       0x90000000 0x10000000   /* non-prefetchable memory */
		       0xa0000000 0x10000000>; /* prefetchable memory */
		interrupts = <0 98 0x04   /* controller interrupt */
		              0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80104000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells = <1>;
		#size-cells = <1>;

		port at 80000000 {
			reg = <0x80000000 0x00001000>;
			status = "disabled";
		};

		port at 80001000 {
			reg = <0x80001000 0x00001000>;
			status = "disabled";
		};
	};

The "ranges" property can probably be cleaned up a bit, but the most interesting part is the port@ children, which can simply be enabled in board DTS files by setting the status property to "okay". I find that somewhat more intuitive to the variant with an "enable-ports" property.

Quoted 6 lines
Quoted 1 line

What do you think of this?

The problem is that children of a PCI-ish bus have specific expectations about the parent address format - the standard 3-address-cell PCI addressing. So making a PCI bus node - even if it is PCIe - with 1 address cell is a problem.

Couldn't you put the #address-cells=<3> underneath each port node, and put any PCIe devices there rather than under the main PCIe controller node? I'm not sure how the interrupt mapping table etc. would work in that case, but that seems to solve the addressing issue.

#28 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 51 lines · Stephen Warren
Quoted 1 line · Mitch Bradley

On 6/12/2012 7:20 AM, Thierry Reding wrote:

...

Quoted 41 lines
Quoted 41 lines

I came up with the following alternative:

	pci {
		compatible = "nvidia,tegra20-pcie";
		reg =<0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000   /* extended configuration space */
		       0x80400000 0x00010000   /* downstream I/O */
		       0x90000000 0x10000000   /* non-prefetchable memory */
		       0xa0000000 0x10000000>; /* prefetchable memory */
		interrupts =<0 98 0x04   /* controller interrupt */
		              0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges =<0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80104000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells =<1>;
		#size-cells =<1>;

		port at 80000000 {
			reg =<0x80000000 0x00001000>;
			status = "disabled";
		};

		port at 80001000 {
			reg =<0x80001000 0x00001000>;
			status = "disabled";
		};
	};

The "ranges" property can probably be cleaned up a bit, but the most interesting part is the port@ children, which can simply be enabled in board DTS files by setting the status property to "okay". I find that somewhat more intuitive to the variant with an "enable-ports" property.

Quoted 6 lines
Quoted 1 line

What do you think of this?

The problem is that children of a PCI-ish bus have specific expectations about the parent address format - the standard 3-address-cell PCI addressing. So making a PCI bus node - even if it is PCIe - with 1 address cell is a problem.

Quoted 4 lines

Couldn't you put the #address-cells=<3> underneath each port node, and put any PCIe devices there rather than under the main PCIe controller node? I'm not sure how the interrupt mapping table etc. would work in that case, but that seems to solve the addressing issue.

Yes, that would work just fine, and in fact would be preferable, if a "root port" is essentially an independent PCI bus. The parent of those root ports should not be named "pci", though, as it is not in itself a PCI bus. It could be called "pcis".

Quoted 2 lines
#29 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 57 lines · Mitch Bradley
Quoted 51 lines · Stephen Warren
Quoted 1 line · Mitch Bradley

On 6/12/2012 7:20 AM, Thierry Reding wrote:

...

Quoted 41 lines
Quoted 41 lines

I came up with the following alternative:

	pci {
		compatible = "nvidia,tegra20-pcie";
		reg =<0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000   /* extended configuration space */
		       0x80400000 0x00010000   /* downstream I/O */
		       0x90000000 0x10000000   /* non-prefetchable memory */
		       0xa0000000 0x10000000>; /* prefetchable memory */
		interrupts =<0 98 0x04   /* controller interrupt */
		              0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges =<0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80104000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells =<1>;
		#size-cells =<1>;

		port at 80000000 {
			reg =<0x80000000 0x00001000>;
			status = "disabled";
		};

		port at 80001000 {
			reg =<0x80001000 0x00001000>;
			status = "disabled";
		};
	};

The "ranges" property can probably be cleaned up a bit, but the most interesting part is the port@ children, which can simply be enabled in board DTS files by setting the status property to "okay". I find that somewhat more intuitive to the variant with an "enable-ports" property.

Quoted 6 lines
Quoted 1 line

What do you think of this?

The problem is that children of a PCI-ish bus have specific expectations about the parent address format - the standard 3-address-cell PCI addressing. So making a PCI bus node - even if it is PCIe - with 1 address cell is a problem.

Quoted 4 lines

Couldn't you put the #address-cells=<3> underneath each port node, and put any PCIe devices there rather than under the main PCIe controller node? I'm not sure how the interrupt mapping table etc. would work in that case, but that seems to solve the addressing issue.

Quoted 4 lines

Yes, that would work just fine, and in fact would be preferable, if a "root port" is essentially an independent PCI bus. The parent of those root ports should not be named "pci", though, as it is not in itself a PCI bus. It could be called "pcis".

Yes, on Tegra each of the ports provides a separate PCI bus. How about naming the parent "pcie-controller"? IMO that reflects the nature of the device better, whereas "pcis" would seem more like a "virtual" node for collecting similar children.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120613/e7746e30/attachment-0001.sig>

#30 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 58 lines · Thierry Reding
Quoted 57 lines · Mitch Bradley
Quoted 55 lines · Stephen Warren
Quoted 1 line · Mitch Bradley

On 6/12/2012 7:20 AM, Thierry Reding wrote:

...

Quoted 41 lines
Quoted 41 lines

I came up with the following alternative:

	pci {
		compatible = "nvidia,tegra20-pcie";
		reg =<0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000   /* extended configuration space */
		       0x80400000 0x00010000   /* downstream I/O */
		       0x90000000 0x10000000   /* non-prefetchable memory */
		       0xa0000000 0x10000000>; /* prefetchable memory */
		interrupts =<0 98 0x04   /* controller interrupt */
		              0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges =<0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80104000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells =<1>;
		#size-cells =<1>;

		port at 80000000 {
			reg =<0x80000000 0x00001000>;
			status = "disabled";
		};

		port at 80001000 {
			reg =<0x80001000 0x00001000>;
			status = "disabled";
		};
	};

The "ranges" property can probably be cleaned up a bit, but the most interesting part is the port@ children, which can simply be enabled in board DTS files by setting the status property to "okay". I find that somewhat more intuitive to the variant with an "enable-ports" property.

Quoted 6 lines
Quoted 1 line

What do you think of this?

The problem is that children of a PCI-ish bus have specific expectations about the parent address format - the standard 3-address-cell PCI addressing. So making a PCI bus node - even if it is PCIe - with 1 address cell is a problem.

Couldn't you put the #address-cells=<3> underneath each port node, and
put any PCIe devices there rather than under the main PCIe controller node? I'm not sure how the interrupt mapping table etc. would work in that case, but that seems to solve the addressing issue.

Quoted 7 lines
Quoted 4 lines

Yes, that would work just fine, and in fact would be preferable, if a "root port" is essentially an independent PCI bus. The parent of those root ports should not be named "pci", though, as it is not in itself a PCI bus. It could be called "pcis".

Yes, on Tegra each of the ports provides a separate PCI bus. How about naming the parent "pcie-controller"?

That seems like a fine name.

Quoted 5 lines

IMO that reflects the nature of the device
better, whereas "pcis" would seem more like a "virtual" node for collecting similar children.

Thierry

#31 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

In reply to Thierry Reding

On 06/12/2012 11:20 AM, Thierry Reding wrote:
...

Quoted 36 lines

I came up with the following alternative:

	pci {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000   /* extended configuration space */
		       0x80400000 0x00010000   /* downstream I/O */
		       0x90000000 0x10000000   /* non-prefetchable memory */
		       0xa0000000 0x10000000>; /* prefetchable memory */
		interrupts = <0 98 0x04   /* controller interrupt */
		              0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80104000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells = <1>;
		#size-cells = <1>;

		port at 80000000 {
			reg = <0x80000000 0x00001000>;
			status = "disabled";
		};

		port at 80001000 {
			reg = <0x80001000 0x00001000>;
			status = "disabled";
		};
	};
Quoted 6 lines

The "ranges" property can probably be cleaned up a bit, but the most interesting part is the port@ children, which can simply be enabled in board DTS files by setting the status property to "okay". I find that somewhat more intuitive to the variant with an "enable-ports" property.

What do you think of this?

As a general concept, this kind of design seems OK to me.

The "port" child nodes I think should be named "pci at ..." given Mitch's comments, I think.

The port nodes probably need two entries in reg, given the following in our downstream driver:

Quoted 2 lines
        int rp_offset = 0;
        int ctrl_offset = AFI_PEX0_CTRL;

...

Quoted 6 lines
        for (port = 0; port < MAX_PCIE_SUPPORTED_PORTS; port++) {
                ctrl_offset += (port * 8);
                rp_offset = (rp_offset + 0x1000) * port;
                if (tegra_pcie.plat_data->port_status[port])
                        tegra_pcie_add_port(port, rp_offset, ctrl_offset);
        }

(which actually looks likely to be horribly buggy for port>1 and only accidentally correct for port==1, but anyway...)

But instead, I'd be tempted to make the top-level node say:

	#address-cells = <1>;
	#size-cells = <0>;

... so that the child nodes' reg is just the port ID. The parent node can calculate the addresses/offsets of the per-port registers within the PCIe controller's register space based on the ID using code roughly like what I quoted above:

	pci at 0 {
		reg = <0>;
		status = "disabled";
	};

	pci at 1 {
		reg = <0>;
		status = "disabled";
	};

That would save having to put 2 entries in the reg, and perhaps remove the need for any ranges property.

I think you also need a property to specify the exact port layout; the Tegra20 controller supports:

1 x4 port
2 x2 ports (you can choose to use only 1 of these I assume)

So just because only 1 of the ports is enabled, doesn't imply it's x4; it could still be x2.

Tegra30 has more options.

#32 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 76 lines · Stephen Warren

On 06/12/2012 11:20 AM, Thierry Reding wrote:
...

Quoted 36 lines

I came up with the following alternative:

	pci {
		compatible = "nvidia,tegra20-pcie";
		reg =<0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000   /* extended configuration space */
		       0x80400000 0x00010000   /* downstream I/O */
		       0x90000000 0x10000000   /* non-prefetchable memory */
		       0xa0000000 0x10000000>; /* prefetchable memory */
		interrupts =<0 98 0x04   /* controller interrupt */
		              0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges =<0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80104000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells =<1>;
		#size-cells =<1>;

		port at 80000000 {
			reg =<0x80000000 0x00001000>;
			status = "disabled";
		};

		port at 80001000 {
			reg =<0x80001000 0x00001000>;
			status = "disabled";
		};
	};
Quoted 6 lines

The "ranges" property can probably be cleaned up a bit, but the most interesting part is the port@ children, which can simply be enabled in board DTS files by setting the status property to "okay". I find that somewhat more intuitive to the variant with an "enable-ports" property.

What do you think of this?

As a general concept, this kind of design seems OK to me.

The "port" child nodes I think should be named "pci at ..." given Mitch's comments, I think.

The port nodes probably need two entries in reg, given the following in our downstream driver:

Quoted 2 lines
         int rp_offset = 0;
         int ctrl_offset = AFI_PEX0_CTRL;

...

Quoted 6 lines
         for (port = 0; port<  MAX_PCIE_SUPPORTED_PORTS; port++) {
                 ctrl_offset += (port * 8);
                 rp_offset = (rp_offset + 0x1000) * port;
                 if (tegra_pcie.plat_data->port_status[port])
                         tegra_pcie_add_port(port, rp_offset, ctrl_offset);
         }

(which actually looks likely to be horribly buggy for port>1 and only accidentally correct for port==1, but anyway...)

But instead, I'd be tempted to make the top-level node say:

	#address-cells =<1>;
	#size-cells =<0>;

... so that the child nodes' reg is just the port ID. The parent node can calculate the addresses/offsets of the per-port registers within the PCIe controller's register space based on the ID using code roughly like what I quoted above:

Quoted 9 lines
	pci at 0 {
		reg =<0>;
		status = "disabled";
	};

	pci at 1 {
		reg =<0>;
		status = "disabled";
	};

reg = <1> ?

Quoted 4 lines

That would save having to put 2 entries in the reg, and perhaps remove the need for any ranges property.

ISTM that having two reg entries, specifying the rp and ctrl registers, is preferable to having code to calculate the addresses. That makes the code simpler and the device tree more directly descriptive of the hardware layout. The less "magic" (in this case, the register address calculation), the better.

Quoted 17 lines

I think you also need a property to specify the exact port layout; the Tegra20 controller supports:

1 x4 port
2 x2 ports (you can choose to use only 1 of these I assume)

So just because only 1 of the ports is enabled, doesn't imply it's x4; it could still be x2.

Tegra30 has more options.
_______________________________________________
devicetree-discuss mailing list
devicetree-discuss at lists.ozlabs.org
https://lists.ozlabs.org/listinfo/devicetree-discuss

#33 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 90 lines · Mitch Bradley
Quoted 76 lines · Stephen Warren

On 06/12/2012 11:20 AM, Thierry Reding wrote:
...

Quoted 36 lines

I came up with the following alternative:

	pci {
		compatible = "nvidia,tegra20-pcie";
		reg =<0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000   /* extended configuration space */
		       0x80400000 0x00010000   /* downstream I/O */
		       0x90000000 0x10000000   /* non-prefetchable memory */
		       0xa0000000 0x10000000>; /* prefetchable memory */
		interrupts =<0 98 0x04   /* controller interrupt */
		              0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges =<0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80104000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells =<1>;
		#size-cells =<1>;

		port at 80000000 {
			reg =<0x80000000 0x00001000>;
			status = "disabled";
		};

		port at 80001000 {
			reg =<0x80001000 0x00001000>;
			status = "disabled";
		};
	};
Quoted 6 lines

The "ranges" property can probably be cleaned up a bit, but the most interesting part is the port@ children, which can simply be enabled in board DTS files by setting the status property to "okay". I find that somewhat more intuitive to the variant with an "enable-ports" property.

What do you think of this?

As a general concept, this kind of design seems OK to me.

The "port" child nodes I think should be named "pci at ..." given Mitch's comments, I think.

The port nodes probably need two entries in reg, given the following in our downstream driver:

Quoted 2 lines
        int rp_offset = 0;
        int ctrl_offset = AFI_PEX0_CTRL;

...

Quoted 6 lines
        for (port = 0; port<  MAX_PCIE_SUPPORTED_PORTS; port++) {
                ctrl_offset += (port * 8);
                rp_offset = (rp_offset + 0x1000) * port;
                if (tegra_pcie.plat_data->port_status[port])
                        tegra_pcie_add_port(port, rp_offset, ctrl_offset);
        }

(which actually looks likely to be horribly buggy for port>1 and only accidentally correct for port==1, but anyway...)

But instead, I'd be tempted to make the top-level node say:

	#address-cells =<1>;
	#size-cells =<0>;

... so that the child nodes' reg is just the port ID. The parent node can calculate the addresses/offsets of the per-port registers within the PCIe controller's register space based on the ID using code roughly like what I quoted above:

Quoted 9 lines
	pci at 0 {
		reg =<0>;
		status = "disabled";
	};

	pci at 1 {
		reg =<0>;
		status = "disabled";
	};

reg = <1> ?

Quoted 2 lines
Quoted 8 lines
Quoted 2 lines

That would save having to put 2 entries in the reg, and perhaps remove the need for any ranges property.

ISTM that having two reg entries, specifying the rp and ctrl registers, is preferable to having code to calculate the addresses. That makes the code simpler and the device tree more directly descriptive of the hardware layout. The less "magic" (in this case, the register address calculation), the better.

The problem with this approach is that since the control registers are within the AFI register range, both the reg and ranges properties of the parent would have to include these holes. Furthermore it means that the controller driver would have to remap the AFI registers in chunks, for the sole reason of splitting out the controle registers.

Would it be acceptable to make an exception in this case and use the port's second reg entry as an offset into the AFI register range instead?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120613/5cf617b5/attachment.sig>

#34 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 100 lines · Thierry Reding
Quoted 90 lines · Mitch Bradley
Quoted 76 lines · Stephen Warren

On 06/12/2012 11:20 AM, Thierry Reding wrote:
...

Quoted 36 lines

I came up with the following alternative:

	pci {
		compatible = "nvidia,tegra20-pcie";
		reg =<0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000   /* extended configuration space */
		       0x80400000 0x00010000   /* downstream I/O */
		       0x90000000 0x10000000   /* non-prefetchable memory */
		       0xa0000000 0x10000000>; /* prefetchable memory */
		interrupts =<0 98 0x04   /* controller interrupt */
		              0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges =<0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80104000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells =<1>;
		#size-cells =<1>;

		port at 80000000 {
			reg =<0x80000000 0x00001000>;
			status = "disabled";
		};

		port at 80001000 {
			reg =<0x80001000 0x00001000>;
			status = "disabled";
		};
	};
Quoted 6 lines

The "ranges" property can probably be cleaned up a bit, but the most interesting part is the port@ children, which can simply be enabled in board DTS files by setting the status property to "okay". I find that somewhat more intuitive to the variant with an "enable-ports" property.

What do you think of this?

As a general concept, this kind of design seems OK to me.

The "port" child nodes I think should be named "pci at ..." given Mitch's comments, I think.

The port nodes probably need two entries in reg, given the following in our downstream driver:

Quoted 2 lines
         int rp_offset = 0;
         int ctrl_offset = AFI_PEX0_CTRL;

...

Quoted 6 lines
         for (port = 0; port<   MAX_PCIE_SUPPORTED_PORTS; port++) {
                 ctrl_offset += (port * 8);
                 rp_offset = (rp_offset + 0x1000) * port;
                 if (tegra_pcie.plat_data->port_status[port])
                         tegra_pcie_add_port(port, rp_offset, ctrl_offset);
         }

(which actually looks likely to be horribly buggy for port>1 and only accidentally correct for port==1, but anyway...)

But instead, I'd be tempted to make the top-level node say:

	#address-cells =<1>;
	#size-cells =<0>;

... so that the child nodes' reg is just the port ID. The parent node can calculate the addresses/offsets of the per-port registers within the PCIe controller's register space based on the ID using code roughly like what I quoted above:

Quoted 9 lines
	pci at 0 {
		reg =<0>;
		status = "disabled";
	};

	pci at 1 {
		reg =<0>;
		status = "disabled";
	};

reg =<1> ?

Quoted 2 lines
Quoted 8 lines
Quoted 2 lines

That would save having to put 2 entries in the reg, and perhaps remove the need for any ranges property.

ISTM that having two reg entries, specifying the rp and ctrl registers, is preferable to having code to calculate the addresses. That makes the code simpler and the device tree more directly descriptive of the hardware layout. The less "magic" (in this case, the register address calculation), the better.

Quoted 8 lines

The problem with this approach is that since the control registers are within the AFI register range, both the reg and ranges properties of the parent would have to include these holes. Furthermore it means that the controller driver would have to remap the AFI registers in chunks, for the sole reason of splitting out the controle registers.

Would it be acceptable to make an exception in this case and use the port's second reg entry as an offset into the AFI register range instead?

How about this:

     pcie-controller {
         compatible = "nvidia,tegra20-pcie";
         reg =<0x80003000 0x00000800   /* PADS registers */
               0x80003800 0x00000200>   /* AFI registers */
         interrupts =<0 98 0x04   /* controller interrupt */
                      0 99 0x04>; /* MSI interrupt */
         status = "disabled";

         ranges =<0x80000000 0x80000000 0x00002000   /* 2 root ports */
               0x80004000 0x80004000 0x00100000   /* configuration space */
               0x80104000 0x80104000 0x00100000   /* extended 
configuration space */
               0x80400000 0x80400000 0x00010000   /* downstream I/O */
               0x90000000 0x90000000 0x10000000   /* non-prefetchable 
memory */
               0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

         #address-cells =<1>;
         #size-cells =<1>;

         pci at 80000000 {
             reg =<0x80000000 0x00001000>;
             ctrl-offset =<0x0>;
             status = "disabled";
             #address-cells = <3>;  /* Standard for PCI */
             #size-cells =<2>;      /* Standard for PCI */
             ranges =</* Map from standard PCI child address spaces to 
linear spaces above */>;
         };

         pci at 80001000 {
             reg =<0x80001000 0x00001000>;
             ctrl-offset =<0x8>;
             status = "disabled";
             #address-cells = <3>;  /* Standard for PCI */
             #size-cells =<2>;      /* Standard for PCI */
             ranges =</* Map from standard PCI child address spaces to 
linear spaces above */>;
         };
     };

Using ctrl-offset instead of reg avoids any violation of the usual reg semantics.

Note that the pci subnodes need the full complement of PCI bus node properties.

Quoted 3 lines

Thierry

#35 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 112 lines · Mitch Bradley
Quoted 100 lines · Thierry Reding
Quoted 90 lines · Mitch Bradley
Quoted 76 lines · Stephen Warren

On 06/12/2012 11:20 AM, Thierry Reding wrote:
...

Quoted 36 lines

I came up with the following alternative:

	pci {
		compatible = "nvidia,tegra20-pcie";
		reg =<0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000   /* extended configuration space */
		       0x80400000 0x00010000   /* downstream I/O */
		       0x90000000 0x10000000   /* non-prefetchable memory */
		       0xa0000000 0x10000000>; /* prefetchable memory */
		interrupts =<0 98 0x04   /* controller interrupt */
		              0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges =<0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80104000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells =<1>;
		#size-cells =<1>;

		port at 80000000 {
			reg =<0x80000000 0x00001000>;
			status = "disabled";
		};

		port at 80001000 {
			reg =<0x80001000 0x00001000>;
			status = "disabled";
		};
	};
Quoted 6 lines

The "ranges" property can probably be cleaned up a bit, but the most interesting part is the port@ children, which can simply be enabled in board DTS files by setting the status property to "okay". I find that somewhat more intuitive to the variant with an "enable-ports" property.

What do you think of this?

As a general concept, this kind of design seems OK to me.

The "port" child nodes I think should be named "pci at ..." given Mitch's comments, I think.

The port nodes probably need two entries in reg, given the following in our downstream driver:

Quoted 2 lines
        int rp_offset = 0;
        int ctrl_offset = AFI_PEX0_CTRL;

...

Quoted 6 lines
        for (port = 0; port<   MAX_PCIE_SUPPORTED_PORTS; port++) {
                ctrl_offset += (port * 8);
                rp_offset = (rp_offset + 0x1000) * port;
                if (tegra_pcie.plat_data->port_status[port])
                        tegra_pcie_add_port(port, rp_offset, ctrl_offset);
        }

(which actually looks likely to be horribly buggy for port>1 and only accidentally correct for port==1, but anyway...)

But instead, I'd be tempted to make the top-level node say:

	#address-cells =<1>;
	#size-cells =<0>;

... so that the child nodes' reg is just the port ID. The parent node can calculate the addresses/offsets of the per-port registers within the PCIe controller's register space based on the ID using code roughly like what I quoted above:

Quoted 9 lines
	pci at 0 {
		reg =<0>;
		status = "disabled";
	};

	pci at 1 {
		reg =<0>;
		status = "disabled";
	};

reg =<1> ?

Quoted 2 lines
Quoted 8 lines
Quoted 2 lines

That would save having to put 2 entries in the reg, and perhaps remove the need for any ranges property.

ISTM that having two reg entries, specifying the rp and ctrl registers, is preferable to having code to calculate the addresses. That makes the code simpler and the device tree more directly descriptive of the hardware layout. The less "magic" (in this case, the register address calculation), the better.

Quoted 8 lines

The problem with this approach is that since the control registers are within the AFI register range, both the reg and ranges properties of the parent would have to include these holes. Furthermore it means that the controller driver would have to remap the AFI registers in chunks, for the sole reason of splitting out the controle registers.

Would it be acceptable to make an exception in this case and use the port's second reg entry as an offset into the AFI register range instead?

How about this:

Quoted 16 lines
    pcie-controller {
        compatible = "nvidia,tegra20-pcie";
        reg =<0x80003000 0x00000800   /* PADS registers */
              0x80003800 0x00000200>   /* AFI registers */
        interrupts =<0 98 0x04   /* controller interrupt */
                     0 99 0x04>; /* MSI interrupt */
        status = "disabled";

        ranges =<0x80000000 0x80000000 0x00002000   /* 2 root ports */
              0x80004000 0x80004000 0x00100000   /* configuration space */
              0x80104000 0x80104000 0x00100000   /* extended
configuration space */
              0x80400000 0x80400000 0x00010000   /* downstream I/O */
              0x90000000 0x90000000 0x10000000   /* non-prefetchable
memory */
              0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

I think the configuration spaces and downstream I/O ranges need to be in the pcie-controller's reg property because they are remapped and used by the controller driver, not by the individual ports.

That's probably not really necessary but rather a result of how the driver was written. Perhaps the driver should handle them differently instead, listing the regions in the ranges property of the parent and listing the corresponding partitions in the ranges properties of the pci child nodes.

Like in the following, where the ranges property of the ports partition the ranges passed from the parent evenly:

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200>; /* AFI registers */
		interrupts = <0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80100000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells = <1>;
		#size-cells = <1>;

		pci at 80000000 {
			reg = <0x80000000 0x00001000>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x80400000 0x80400000 0x00008000   /* I/O */
				  0x90000000 0x90000000 0x08000000   /* non-prefetchable memory */
				  0xa0000000 0xa0000000 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x0>;
			nvidia,num-lanes = <2>;
		};

		pci at 80001000 {
			reg = <0x80001000 0x00001000>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x80408000 0x80408000 0x00008000   /* I/O */
				  0x98000000 0x98000000 0x08000000   /* non-prefetchable memory */
				  0xa8000000 0xa8000000 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x8>;
			nvidia,num-lanes = <2>;
		};
	};

I've also added the new num-lanes property that describes the physical connections of the port. Also the ctrl-offset and num-lanes property are pretty specific to the Tegra PCIe controller, so I've prefixed them with "nvidia,".

Quoted 25 lines
        #address-cells =<1>;
        #size-cells =<1>;

        pci at 80000000 {
            reg =<0x80000000 0x00001000>;
            ctrl-offset =<0x0>;
            status = "disabled";
            #address-cells = <3>;  /* Standard for PCI */
            #size-cells =<2>;      /* Standard for PCI */
            ranges =</* Map from standard PCI child address spaces
to linear spaces above */>;
        };

        pci at 80001000 {
            reg =<0x80001000 0x00001000>;
            ctrl-offset =<0x8>;
            status = "disabled";
            #address-cells = <3>;  /* Standard for PCI */
            #size-cells =<2>;      /* Standard for PCI */
            ranges =</* Map from standard PCI child address spaces
to linear spaces above */>;
        };
    };
Quoted 2 lines

Using ctrl-offset instead of reg avoids any violation of the usual reg semantics.

Yes, that sounds better.

Quoted 8 lines

Note that the pci subnodes need the full complement of PCI bus node properties.

Quoted 3 lines

Thierry

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120613/f40d07c2/attachment.sig>

#36 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 162 lines · Thierry Reding
Quoted 112 lines · Mitch Bradley
Quoted 100 lines · Thierry Reding
Quoted 90 lines · Mitch Bradley
Quoted 76 lines · Stephen Warren

On 06/12/2012 11:20 AM, Thierry Reding wrote:
...

Quoted 36 lines

I came up with the following alternative:

	pci {
		compatible = "nvidia,tegra20-pcie";
		reg =<0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000   /* extended configuration space */
		       0x80400000 0x00010000   /* downstream I/O */
		       0x90000000 0x10000000   /* non-prefetchable memory */
		       0xa0000000 0x10000000>; /* prefetchable memory */
		interrupts =<0 98 0x04   /* controller interrupt */
		              0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges =<0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80104000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells =<1>;
		#size-cells =<1>;

		port at 80000000 {
			reg =<0x80000000 0x00001000>;
			status = "disabled";
		};

		port at 80001000 {
			reg =<0x80001000 0x00001000>;
			status = "disabled";
		};
	};
Quoted 6 lines

The "ranges" property can probably be cleaned up a bit, but the most interesting part is the port@ children, which can simply be enabled in board DTS files by setting the status property to "okay". I find that somewhat more intuitive to the variant with an "enable-ports" property.

What do you think of this?

As a general concept, this kind of design seems OK to me.

The "port" child nodes I think should be named "pci at ..." given Mitch's comments, I think.

The port nodes probably need two entries in reg, given the following in our downstream driver:

Quoted 2 lines
         int rp_offset = 0;
         int ctrl_offset = AFI_PEX0_CTRL;

...

Quoted 6 lines
         for (port = 0; port<    MAX_PCIE_SUPPORTED_PORTS; port++) {
                 ctrl_offset += (port * 8);
                 rp_offset = (rp_offset + 0x1000) * port;
                 if (tegra_pcie.plat_data->port_status[port])
                         tegra_pcie_add_port(port, rp_offset, ctrl_offset);
         }

(which actually looks likely to be horribly buggy for port>1 and only accidentally correct for port==1, but anyway...)

But instead, I'd be tempted to make the top-level node say:

	#address-cells =<1>;
	#size-cells =<0>;

... so that the child nodes' reg is just the port ID. The parent node can calculate the addresses/offsets of the per-port registers within the PCIe controller's register space based on the ID using code roughly like what I quoted above:

Quoted 9 lines
	pci at 0 {
		reg =<0>;
		status = "disabled";
	};

	pci at 1 {
		reg =<0>;
		status = "disabled";
	};

reg =<1> ?

Quoted 2 lines
Quoted 8 lines
Quoted 2 lines

That would save having to put 2 entries in the reg, and perhaps remove the need for any ranges property.

ISTM that having two reg entries, specifying the rp and ctrl registers, is preferable to having code to calculate the addresses. That makes the code simpler and the device tree more directly descriptive of the hardware layout. The less "magic" (in this case, the register address calculation), the better.

Quoted 8 lines

The problem with this approach is that since the control registers are within the AFI register range, both the reg and ranges properties of the parent would have to include these holes. Furthermore it means that the controller driver would have to remap the AFI registers in chunks, for the sole reason of splitting out the controle registers.

Would it be acceptable to make an exception in this case and use the port's second reg entry as an offset into the AFI register range instead?

How about this:

Quoted 16 lines
     pcie-controller {
         compatible = "nvidia,tegra20-pcie";
         reg =<0x80003000 0x00000800   /* PADS registers */
               0x80003800 0x00000200>    /* AFI registers */
         interrupts =<0 98 0x04   /* controller interrupt */
                      0 99 0x04>; /* MSI interrupt */
         status = "disabled";

         ranges =<0x80000000 0x80000000 0x00002000   /* 2 root ports */
               0x80004000 0x80004000 0x00100000   /* configuration space */
               0x80104000 0x80104000 0x00100000   /* extended
configuration space */
               0x80400000 0x80400000 0x00010000   /* downstream I/O */
               0x90000000 0x90000000 0x10000000   /* non-prefetchable
memory */
               0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

I think the configuration spaces and downstream I/O ranges need to be in the pcie-controller's reg property because they are remapped and used by the controller driver, not by the individual ports.

That's probably not really necessary but rather a result of how the driver was written. Perhaps the driver should handle them differently instead, listing the regions in the ranges property of the parent and listing the corresponding partitions in the ranges properties of the pci child nodes.

Like in the following, where the ranges property of the ports partition the ranges passed from the parent evenly:

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg =<0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200>; /* AFI registers */
		interrupts =<0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges =<0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80100000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells =<1>;
		#size-cells =<1>;

		pci at 80000000 {
			reg =<0x80000000 0x00001000>;
Quoted 8 lines
			status = "disabled";

			#address-cells =<3>;
			#size-cells =<2>;

			ranges =<0x80400000 0x80400000 0x00008000   /* I/O */
				  0x90000000 0x90000000 0x08000000   /* non-prefetchable memory */
				  0xa0000000 0xa0000000 0x08000000>; /* prefetchable memory */

You are on the right track here, but the format of the child-address portion of the above ranges property is incorrect. Since the child address space is the PCI address space, the child-address portion needs to be 3 cells. It's not a linear address but rather a triple. The first cell identifies the address type (config, I/O, memory..) and the second and third cells are offsets within that subspace. The second and third cells will typically be 0. The PCI binding has details.

Quoted 65 lines

			nvidia,ctrl-offset =<0x0>;
			nvidia,num-lanes =<2>;
		};

		pci at 80001000 {
			reg =<0x80001000 0x00001000>;
			status = "disabled";

			#address-cells =<3>;
			#size-cells =<2>;

			ranges =<0x80408000 0x80408000 0x00008000   /* I/O */
				  0x98000000 0x98000000 0x08000000   /* non-prefetchable memory */
				  0xa8000000 0xa8000000 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset =<0x8>;
			nvidia,num-lanes =<2>;
		};
	};

I've also added the new num-lanes property that describes the physical connections of the port. Also the ctrl-offset and num-lanes property are pretty specific to the Tegra PCIe controller, so I've prefixed them with "nvidia,".

Quoted 25 lines
         #address-cells =<1>;
         #size-cells =<1>;

         pci at 80000000 {
             reg =<0x80000000 0x00001000>;
             ctrl-offset =<0x0>;
             status = "disabled";
             #address-cells =<3>;  /* Standard for PCI */
             #size-cells =<2>;      /* Standard for PCI */
             ranges =</* Map from standard PCI child address spaces
to linear spaces above */>;
         };

         pci at 80001000 {
             reg =<0x80001000 0x00001000>;
             ctrl-offset =<0x8>;
             status = "disabled";
             #address-cells =<3>;  /* Standard for PCI */
             #size-cells =<2>;      /* Standard for PCI */
             ranges =</* Map from standard PCI child address spaces
to linear spaces above */>;
         };
     };
Quoted 2 lines

Using ctrl-offset instead of reg avoids any violation of the usual reg semantics.

Yes, that sounds better.

Quoted 8 lines

Note that the pci subnodes need the full complement of PCI bus node properties.

Quoted 3 lines

Thierry

#37 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 42 lines · Mitch Bradley
Quoted 32 lines · Thierry Reding

I think the configuration spaces and downstream I/O ranges need to be in the pcie-controller's reg property because they are remapped and used by the controller driver, not by the individual ports.

That's probably not really necessary but rather a result of how the driver was written. Perhaps the driver should handle them differently instead, listing the regions in the ranges property of the parent and listing the corresponding partitions in the ranges properties of the pci child nodes.

Like in the following, where the ranges property of the ports partition the ranges passed from the parent evenly:

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg =<0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200>; /* AFI registers */
		interrupts =<0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges =<0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80100000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells =<1>;
		#size-cells =<1>;

		pci at 80000000 {
			reg =<0x80000000 0x00001000>;
Quoted 8 lines
			status = "disabled";

			#address-cells =<3>;
			#size-cells =<2>;

			ranges =<0x80400000 0x80400000 0x00008000   /* I/O */
				  0x90000000 0x90000000 0x08000000   /* non-prefetchable memory */
				  0xa0000000 0xa0000000 0x08000000>; /* prefetchable memory */
Quoted 8 lines

You are on the right track here, but the format of the child-address portion of the above ranges property is incorrect. Since the child address space is the PCI address space, the child-address portion needs to be 3 cells. It's not a linear address but rather a triple. The first cell identifies the address type (config, I/O, memory..) and the second and third cells are offsets within that subspace. The second and third cells will typically be 0. The PCI binding has details.

Okay, I'll need to read up some more.

Thanks,
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120613/5013e334/attachment-0001.sig>

#38 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 43 lines · Thierry Reding
Quoted 42 lines · Mitch Bradley
Quoted 40 lines · Thierry Reding

I think the configuration spaces and downstream I/O ranges need to be in the pcie-controller's reg property because they are remapped and used by the controller driver, not by the individual ports.

That's probably not really necessary but rather a result of how the driver was written. Perhaps the driver should handle them differently instead, listing the regions in the ranges property of the parent and listing the corresponding partitions in the ranges properties of the pci child nodes.

Like in the following, where the ranges property of the ports partition the ranges passed from the parent evenly:

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg =<0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200>; /* AFI registers */
		interrupts =<0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges =<0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80100000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells =<1>;
		#size-cells =<1>;

		pci at 80000000 {
			reg =<0x80000000 0x00001000>;
			status = "disabled";

			#address-cells =<3>;
			#size-cells =<2>;

			ranges =<0x80400000 0x80400000 0x00008000   /* I/O */
				  0x90000000 0x90000000 0x08000000   /* non-prefetchable memory */
				  0xa0000000 0xa0000000 0x08000000>; /* prefetchable memory */
Quoted 8 lines
Quoted 8 lines

You are on the right track here, but the format of the child-address portion of the above ranges property is incorrect. Since the child address space is the PCI address space, the child-address portion needs to be 3 cells. It's not a linear address but rather a triple. The first cell identifies the address type (config, I/O, memory..) and the second and third cells are offsets within that subspace. The second and third cells will typically be 0. The PCI binding has details.

Also, the size field in ranges is specified according to the child address space, so there must be 2 size cells in the ranges at this level. Each ranges entry at this level is:

<child_address_space, child_address_high, child_address_low, parent_address, child_size_high, child_size_low>

The above should be:

			ranges =<0x81000000 0 0  0x80400000  0 0x00008000   /* I/O */
				 0x82000000 0 0  0x90000000  0 0x08000000   /* non-prefetchable memory */
				 0xc2000000 0 0  0xa0000000  0 0x08000000>; /* prefetchable memory */
Quoted 6 lines
Quoted 1 line

Okay, I'll need to read up some more.

Thanks,
Thierry

#39 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 57 lines · Mitch Bradley
Quoted 43 lines · Thierry Reding
Quoted 42 lines · Mitch Bradley
Quoted 40 lines · Thierry Reding

I think the configuration spaces and downstream I/O ranges need to be in the pcie-controller's reg property because they are remapped and used by the controller driver, not by the individual ports.

That's probably not really necessary but rather a result of how the driver was written. Perhaps the driver should handle them differently instead, listing the regions in the ranges property of the parent and listing the corresponding partitions in the ranges properties of the pci child nodes.

Like in the following, where the ranges property of the ports partition the ranges passed from the parent evenly:

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg =<0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200>; /* AFI registers */
		interrupts =<0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges =<0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80100000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells =<1>;
		#size-cells =<1>;

		pci at 80000000 {
			reg =<0x80000000 0x00001000>;
			status = "disabled";

			#address-cells =<3>;
			#size-cells =<2>;

			ranges =<0x80400000 0x80400000 0x00008000   /* I/O */
				  0x90000000 0x90000000 0x08000000   /* non-prefetchable memory */
				  0xa0000000 0xa0000000 0x08000000>; /* prefetchable memory */
Quoted 8 lines
Quoted 8 lines

You are on the right track here, but the format of the child-address portion of the above ranges property is incorrect. Since the child address space is the PCI address space, the child-address portion needs to be 3 cells. It's not a linear address but rather a triple. The first cell identifies the address type (config, I/O, memory..) and the second and third cells are offsets within that subspace. The second and third cells will typically be 0. The PCI binding has details.

Also, the size field in ranges is specified according to the child address space, so there must be 2 size cells in the ranges at this level. Each ranges entry at this level is:

Quoted 8 lines

<child_address_space, child_address_high, child_address_low, parent_address, child_size_high, child_size_low>

The above should be:

			ranges =<0x81000000 0 0  0x80400000  0 0x00008000   /* I/O */
				 0x82000000 0 0  0x90000000  0 0x08000000   /* non-prefetchable memory */
				 0xc2000000 0 0  0xa0000000  0 0x08000000>; /* prefetchable memory */

Okay, I think I'm beginning to understand. Thanks.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120613/2a5d3c12/attachment.sig>

#40 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

In reply to Mitch Bradley
Quoted 57 lines · Mitch Bradley
Quoted 43 lines · Thierry Reding
Quoted 42 lines · Mitch Bradley
Quoted 40 lines · Thierry Reding

I think the configuration spaces and downstream I/O ranges need to be in the pcie-controller's reg property because they are remapped and used by the controller driver, not by the individual ports.

That's probably not really necessary but rather a result of how the driver was written. Perhaps the driver should handle them differently instead, listing the regions in the ranges property of the parent and listing the corresponding partitions in the ranges properties of the pci child nodes.

Like in the following, where the ranges property of the ports partition the ranges passed from the parent evenly:

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg =<0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200>; /* AFI registers */
		interrupts =<0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges =<0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80100000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells =<1>;
		#size-cells =<1>;

		pci at 80000000 {
			reg =<0x80000000 0x00001000>;
			status = "disabled";

			#address-cells =<3>;
			#size-cells =<2>;

			ranges =<0x80400000 0x80400000 0x00008000   /* I/O */
				  0x90000000 0x90000000 0x08000000   /* non-prefetchable memory */
				  0xa0000000 0xa0000000 0x08000000>; /* prefetchable memory */
Quoted 8 lines
Quoted 8 lines

You are on the right track here, but the format of the child-address portion of the above ranges property is incorrect. Since the child address space is the PCI address space, the child-address portion needs to be 3 cells. It's not a linear address but rather a triple. The first cell identifies the address type (config, I/O, memory..) and the second and third cells are offsets within that subspace. The second and third cells will typically be 0. The PCI binding has details.

Also, the size field in ranges is specified according to the child address space, so there must be 2 size cells in the ranges at this level. Each ranges entry at this level is:

Quoted 10 lines

<child_address_space, child_address_high, child_address_low, parent_address, child_size_high, child_size_low>

The above should be:

			ranges =<0x81000000 0 0  0x80400000  0 0x00008000   /* I/O */
				 0x82000000 0 0  0x90000000  0 0x08000000   /* non-prefetchable memory */
				 0xc2000000 0 0  0xa0000000  0 0x08000000>; /* prefetchable memory */

Okay, so the new pcie-controller node looks like this:

	pcie-controller {
		compatible = "nvidia,tegra20-pcie", "simple-bus";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000>; /* extended configuration space */
		interrupts = <0 98 0x04   /* controller interrupt */
		              0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells = <1>;
		#size-cells = <1>;

		pci at 80000000 {
			compatible = "nvidia,tegra20-pcie-port";
			reg = <0x80000000 0x00001000>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x81000000 0 0 0x80400000 0 0x00008000   /* I/O */
				  0x82000000 0 0 0x90000000 0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0 0xa0000000 0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x110>;
			nvidia,num-lanes = <2>;
		};

		pci at 80001000 {
			compatible = "nvidia,tegra20-pcie-port";
			reg = <0x80001000 0x00001000>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x81000000 0 0 0x80408000 0 0x00008000   /* I/O */
				  0x82000000 0 0 0x98000000 0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0 0xa8000000 0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x118>;
			nvidia,num-lanes = <2>;
		};
	};

While looking into some more code, trying to figure out how to hook this all up with the device tree I ran into a problem. I need to actually create a 'struct device' for each of the ports, so I added the "simple-bus" to the pcie-controller's "compatible" property. Furthermore, each PCI root port now becomes a platform_device, which are supported by a new tegra-pcie-port driver. I'm not sure if "port" is very common in PCI speek, so something like tegra-pcie-bridge (compatible = "nvidia,tegra20-pcie-bridge") may be more appropriate?

Using real platform devices is not only more straightforward (each bridge is after all a separate parent for the PCI endpoints) but it also has the advantage that the bridges are properly hooked up with the device tree. If I read the code correctly, passing the 'struct device' to pci_scan_root_bus() will allow the PCI core code to set up the proper pointers that allow busses and endpoints below each bridge to be matched to the corresponding DT nodes.

However this causes other problems with the initialization of the PCIe controller. The translations cannot be setup and the controller shouldn't be enabled until after all the ports have been probed because it isn't clear which of them are really active and which are not. For the DT case this can probably be done by parsing the device tree and collecting the information, but for the non-DT case this will probably be more difficult.

To solve this for both cases I could probably use device_for_each_child() and check that all children have been properly probed before setting up the translations and enabling the controller. That leaves the question of how to verify that a device has been correctly probed. The easiest would probably be to check if dev_get_drvdata() != NULL, but I'm still trying to decide whether that's too ugly or not. I don't know of any other way to determine that probing was successful. In addition it may still be useful to continue if one of the devices failed to initialize (the link on only one of two enabled ports is up).

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120614/69eb44a0/attachment-0001.sig>

#41 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

On 06/14/2012 03:19 AM, Thierry Reding wrote:
...

Quoted 9 lines

Okay, so the new pcie-controller node looks like this:

pcie-controller { compatible = "nvidia,tegra20-pcie",
"simple-bus"; reg = <0x80003000 0x00000800 /* PADS registers */
0x80003800 0x00000200 /* AFI registers */ 0x80004000 0x00100000
/* configuration space */ 0x80104000 0x00100000>; /* extended
configuration space */ interrupts = <0 98 0x04 /* controller
interrupt */ 0 99 0x04>; /* MSI interrupt */ status = "disabled";

Quoted 4 lines

ranges = <0x80000000 0x80000000 0x00002000 /* 2 root ports */
0x80400000 0x80400000 0x00010000 /* downstream I/O */ 0x90000000
0x90000000 0x10000000 /* non-prefetchable memory */ 0xa0000000
0xa0000000 0x10000000>; /* prefetchable memory */

Do we actually need to specifically enumerate all the ranges; would just "ranges;" be simpler?

Quoted 3 lines

#address-cells = <1>; #size-cells = <1>;

pci at 80000000 {

I'm still not convinced that using the address of the port's registers is the correct way to represent each port. The port index seems much more useful.

The main reason here is that there are a lot of registers that contain fields for each port - far more than the combination of this node's reg and ctrl-offset (which I assume is an address offset for just one example of this issue) properties can describe. The bit position and bit stride of these fields isn't necessarily the same in each register. Do we want a property like ctrl-offset for every single type of field in every single shared register that describes the location of the relevant data, or just a single "port ID" bit that can be applied to anything?

(Perhaps this isn't so obvious looking at the TRM since it doesn't document all registers, and I'm also looking at the Tegra30 documentation too, which might be more exposed to this - I haven't correlated all the documentation sources to be sure though)

Quoted 9 lines

compatible = "nvidia,tegra20-pcie-port"; reg = <0x80000000 0x00001000>; status = "disabled";

#address-cells = <3>; #size-cells = <2>;

ranges = <0x81000000 0 0 0x80400000 0 0x00008000 /* I/O */
0x82000000 0 0 0x90000000 0 0x08000000 /* non-prefetchable memory
*/ 0xc2000000 0 0 0xa0000000 0 0x08000000>; /* prefetchable memory */

The values here appear identical for both ports. Surely they should describe just the parts of the overall address space that have been assigned/delegated to the individual port/bridge?

Note that initial indications are that the overall controller receives transactions for those address ranges, and standard PCIe bridge registers are used to steer chunks of these address ranges into the individual downstream ports/busses. Hence, standard PCIe documentation should indicate how to do this.

Quoted 14 lines

nvidia,ctrl-offset = <0x110>; nvidia,num-lanes = <2>; };

pci at 80001000 { compatible = "nvidia,tegra20-pcie-port"; reg = <0x80001000 0x00001000>; status = "disabled";

#address-cells = <3>; #size-cells = <2>;

ranges = <0x81000000 0 0 0x80408000 0 0x00008000 /* I/O */
0x82000000 0 0 0x98000000 0 0x08000000 /* non-prefetchable memory
*/ 0xc2000000 0 0 0xa8000000 0 0x08000000>; /* prefetchable memory */

nvidia,ctrl-offset = <0x118>; nvidia,num-lanes = <2>; }; };

Quoted 9 lines

While looking into some more code, trying to figure out how to hook this all up with the device tree I ran into a problem. I need to actually create a 'struct device' for each of the ports, so I added the "simple-bus" to the pcie-controller's "compatible" property. Furthermore, each PCI root port now becomes a platform_device, which are supported by a new tegra-pcie-port driver. I'm not sure if "port" is very common in PCI speek, so something like tegra-pcie-bridge (compatible = "nvidia,tegra20-pcie-bridge") may be more appropriate?

What is it that drives the need for each port to be a 'struct device'? The current driver supports 2 host ports, yet there's only a single struct device for it. Does the DT code assume a 1:1 mapping between struct device and DT node that represents the child bus? If so, perhaps it'd be better to rework that code to accept a DT node as a parameter and call it multiple times, rather than accept a struct device as a parameter and hence need multiple devices?

#42 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 11 lines · Stephen Warren

On 06/14/2012 03:19 AM, Thierry Reding wrote:
...

Quoted 9 lines

Okay, so the new pcie-controller node looks like this:

pcie-controller { compatible = "nvidia,tegra20-pcie",
"simple-bus"; reg = <0x80003000 0x00000800 /* PADS registers */
0x80003800 0x00000200 /* AFI registers */ 0x80004000 0x00100000
/* configuration space */ 0x80104000 0x00100000>; /* extended
configuration space */ interrupts = <0 98 0x04 /* controller
interrupt */ 0 99 0x04>; /* MSI interrupt */ status = "disabled";

Quoted 7 lines
Quoted 4 lines

ranges = <0x80000000 0x80000000 0x00002000 /* 2 root ports */
0x80400000 0x80400000 0x00010000 /* downstream I/O */ 0x90000000
0x90000000 0x10000000 /* non-prefetchable memory */ 0xa0000000
0xa0000000 0x10000000>; /* prefetchable memory */

Do we actually need to specifically enumerate all the ranges; would just "ranges;" be simpler?

I think they need to be listed here in order for the child nodes to be able to map them using their ranges property. It's possible that it'll work by specifying an empty ranges, but I don't think it'd be correct in the OF sense.

Quoted 18 lines
Quoted 3 lines

#address-cells = <1>; #size-cells = <1>;

pci at 80000000 {

I'm still not convinced that using the address of the port's registers is the correct way to represent each port. The port index seems much more useful.

The main reason here is that there are a lot of registers that contain fields for each port - far more than the combination of this node's reg and ctrl-offset (which I assume is an address offset for just one example of this issue) properties can describe. The bit position and bit stride of these fields isn't necessarily the same in each register. Do we want a property like ctrl-offset for every single type of field in every single shared register that describes the location of the relevant data, or just a single "port ID" bit that can be applied to anything?

Quoted 4 lines

(Perhaps this isn't so obvious looking at the TRM since it doesn't document all registers, and I'm also looking at the Tegra30 documentation too, which might be more exposed to this - I haven't correlated all the documentation sources to be sure though)

I agree that maybe adding properties for each bit position or register offset may not work out too well. But I think it still makes sense to use the base address of the port's registers (see below). We could of course add some code to determine the index from the base address at initialization time and reuse the index where appropriate.

Quoted 5 lines
Quoted 5 lines

compatible = "nvidia,tegra20-pcie-port"; reg = <0x80000000 0x00001000>; status = "disabled";

#address-cells = <3>; #size-cells = <2>;

Quoted 8 lines
Quoted 4 lines

ranges = <0x81000000 0 0 0x80400000 0 0x00008000 /* I/O */
0x82000000 0 0 0x90000000 0 0x08000000 /* non-prefetchable memory
*/ 0xc2000000 0 0 0xa0000000 0 0x08000000>; /* prefetchable memory */

The values here appear identical for both ports. Surely they should describe just the parts of the overall address space that have been assigned/delegated to the individual port/bridge?

They're not identical. Port 0 gets the first half and port 1 gets the second half of the ranges specified in the parent.

Quoted 5 lines

Note that initial indications are that the overall controller receives transactions for those address ranges, and standard PCIe bridge registers are used to steer chunks of these address ranges into the individual downstream ports/busses. Hence, standard PCIe documentation should indicate how to do this.

Yes, I believe that works with the code I have currently, which basically parses the ranges property of each port and initializes the I/O, memory and prefetchable regions from those values.

Quoted 24 lines
Quoted 14 lines

nvidia,ctrl-offset = <0x110>; nvidia,num-lanes = <2>; };

pci at 80001000 { compatible = "nvidia,tegra20-pcie-port"; reg = <0x80001000 0x00001000>; status = "disabled";

#address-cells = <3>; #size-cells = <2>;

ranges = <0x81000000 0 0 0x80408000 0 0x00008000 /* I/O */
0x82000000 0 0 0x98000000 0 0x08000000 /* non-prefetchable memory
*/ 0xc2000000 0 0 0xa8000000 0 0x08000000>; /* prefetchable memory */

nvidia,ctrl-offset = <0x118>; nvidia,num-lanes = <2>; }; };

Quoted 9 lines

While looking into some more code, trying to figure out how to hook this all up with the device tree I ran into a problem. I need to actually create a 'struct device' for each of the ports, so I added the "simple-bus" to the pcie-controller's "compatible" property. Furthermore, each PCI root port now becomes a platform_device, which are supported by a new tegra-pcie-port driver. I'm not sure if "port" is very common in PCI speek, so something like tegra-pcie-bridge (compatible = "nvidia,tegra20-pcie-bridge") may be more appropriate?

Quoted 7 lines

What is it that drives the need for each port to be a 'struct device'? The current driver supports 2 host ports, yet there's only a single struct device for it. Does the DT code assume a 1:1 mapping between struct device and DT node that represents the child bus? If so, perhaps it'd be better to rework that code to accept a DT node as a parameter and call it multiple times, rather than accept a struct device as a parameter and hence need multiple devices?

It's not so much the DT code, but rather the PCI core and ultimately the device model that requires it. Each port is basically a PCI host bridge that provides a root PCI bus and the device model is used to represent the hierachy of the busses. Providing just the DT node isn't going to be enough.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120614/d3b0a9d4/attachment-0001.sig>

#43 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 2 lines · Thierry Reding
Quoted 1 line · Stephen Warren

On 06/14/2012 03:19 AM, Thierry Reding wrote:

...

Quoted 24 lines
Quoted 18 lines
Quoted 3 lines

#address-cells = <1>; #size-cells = <1>;

pci at 80000000 {

I'm still not convinced that using the address of the port's registers is the correct way to represent each port. The port index seems much more useful.

The main reason here is that there are a lot of registers that contain fields for each port - far more than the combination of this node's reg and ctrl-offset (which I assume is an address offset for just one example of this issue) properties can describe. The bit position and bit stride of these fields isn't necessarily the same in each register. Do we want a property like ctrl-offset for every single type of field in every single shared register that describes the location of the relevant data, or just a single "port ID" bit that can be applied to anything?

Quoted 5 lines

(Perhaps this isn't so obvious looking at the TRM since it doesn't document all registers, and I'm also looking at the Tegra30 documentation too, which might be more exposed to this - I haven't correlated all the documentation sources to be sure though)

Quoted 6 lines

I agree that maybe adding properties for each bit position or register offset may not work out too well. But I think it still makes sense to use the base address of the port's registers (see below). We could of course add some code to determine the index from the base address at initialization time and reuse the index where appropriate.

To me, working back from address to ID then using the ID to calculate some other addresses seems far more icky than just calculating all the addresses based off of one ID. But, I suppose this doesn't make a huge practical difference.

Quoted 10 lines
Quoted 10 lines
Quoted 9 lines

compatible = "nvidia,tegra20-pcie-port"; reg = <0x80000000 0x00001000>; status = "disabled";

#address-cells = <3>; #size-cells = <2>;

ranges = <0x81000000 0 0 0x80400000 0 0x00008000 /* I/O */
0x82000000 0 0 0x90000000 0 0x08000000 /* non-prefetchable
memory */ 0xc2000000 0 0 0xa0000000 0 0x08000000>; /* prefetchable memory */

Quoted 6 lines
Quoted 3 lines

The values here appear identical for both ports. Surely they should describe just the parts of the overall address space that have been assigned/delegated to the individual port/bridge?

They're not identical. Port 0 gets the first half and port 1 gets the second half of the ranges specified in the parent.

Oh right, I missed some 8s and 0s that looked the same!

Quoted 19 lines
Quoted 10 lines
Quoted 9 lines

While looking into some more code, trying to figure out how to hook this all up with the device tree I ran into a problem. I need to actually create a 'struct device' for each of the ports, so I added the "simple-bus" to the pcie-controller's "compatible" property. Furthermore, each PCI root port now becomes a platform_device, which are supported by a new tegra-pcie-port driver. I'm not sure if "port" is very common in PCI speek, so something like tegra-pcie-bridge (compatible = "nvidia,tegra20-pcie-bridge") may be more appropriate?

Quoted 8 lines

What is it that drives the need for each port to be a 'struct device'? The current driver supports 2 host ports, yet there's only a single struct device for it. Does the DT code assume a 1:1 mapping between struct device and DT node that represents the child bus? If so, perhaps it'd be better to rework that code to accept a DT node as a parameter and call it multiple times, rather than accept a struct device as a parameter and hence need multiple devices?

Quoted 5 lines

It's not so much the DT code, but rather the PCI core and ultimately the device model that requires it. Each port is basically a PCI host bridge that provides a root PCI bus and the device model is used to represent the hierachy of the busses. Providing just the DT node isn't going to be enough.

But the existing driver works without /any/ devices, let alone one per port.

#44 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 35 lines · Stephen Warren
Quoted 2 lines · Thierry Reding
Quoted 1 line · Stephen Warren

On 06/14/2012 03:19 AM, Thierry Reding wrote:

...

Quoted 24 lines
Quoted 18 lines
Quoted 3 lines

#address-cells = <1>; #size-cells = <1>;

pci at 80000000 {

I'm still not convinced that using the address of the port's registers is the correct way to represent each port. The port index seems much more useful.

The main reason here is that there are a lot of registers that contain fields for each port - far more than the combination of this node's reg and ctrl-offset (which I assume is an address offset for just one example of this issue) properties can describe. The bit position and bit stride of these fields isn't necessarily the same in each register. Do we want a property like ctrl-offset for every single type of field in every single shared register that describes the location of the relevant data, or just a single "port ID" bit that can be applied to anything?

Quoted 5 lines

(Perhaps this isn't so obvious looking at the TRM since it doesn't document all registers, and I'm also looking at the Tegra30 documentation too, which might be more exposed to this - I haven't correlated all the documentation sources to be sure though)

Quoted 6 lines

I agree that maybe adding properties for each bit position or register offset may not work out too well. But I think it still makes sense to use the base address of the port's registers (see below). We could of course add some code to determine the index from the base address at initialization time and reuse the index where appropriate.

Quoted 4 lines

To me, working back from address to ID then using the ID to calculate some other addresses seems far more icky than just calculating all the addresses based off of one ID. But, I suppose this doesn't make a huge practical difference.

This really depends on the device vs. no device decision below. If we can make it work without needing an extra device for it, then using the index is certainly better. However, if we instantiate devices from the DT, then we have the address anyway and adding the index as a property would be redundant and error prone (what happens if somebody sets the index of the port at address 0x80000000 to 2?).

Quoted 38 lines
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines

compatible = "nvidia,tegra20-pcie-port"; reg = <0x80000000 0x00001000>; status = "disabled";

#address-cells = <3>; #size-cells = <2>;

ranges = <0x81000000 0 0 0x80400000 0 0x00008000 /* I/O */
0x82000000 0 0 0x90000000 0 0x08000000 /* non-prefetchable
memory */ 0xc2000000 0 0 0xa0000000 0 0x08000000>; /* prefetchable memory */

Quoted 6 lines
Quoted 3 lines

The values here appear identical for both ports. Surely they should describe just the parts of the overall address space that have been assigned/delegated to the individual port/bridge?

They're not identical. Port 0 gets the first half and port 1 gets the second half of the ranges specified in the parent.

Oh right, I missed some 8s and 0s that looked the same!

Quoted 19 lines
Quoted 18 lines
Quoted 9 lines

While looking into some more code, trying to figure out how to hook this all up with the device tree I ran into a problem. I need to actually create a 'struct device' for each of the ports, so I added the "simple-bus" to the pcie-controller's "compatible" property. Furthermore, each PCI root port now becomes a platform_device, which are supported by a new tegra-pcie-port driver. I'm not sure if "port" is very common in PCI speek, so something like tegra-pcie-bridge (compatible = "nvidia,tegra20-pcie-bridge") may be more appropriate?

What is it that drives the need for each port to be a 'struct device'? The current driver supports 2 host ports, yet there's only a single struct device for it. Does the DT code assume a 1:1 mapping between struct device and DT node that represents the child bus? If so, perhaps it'd be better to rework that code to accept a DT node as a parameter and call it multiple times, rather than accept a struct device as a parameter and hence need multiple devices?

Quoted 8 lines
Quoted 5 lines

It's not so much the DT code, but rather the PCI core and ultimately the device model that requires it. Each port is basically a PCI host bridge that provides a root PCI bus and the device model is used to represent the hierachy of the busses. Providing just the DT node isn't going to be enough.

But the existing driver works without /any/ devices, let alone one per port.

That doesn't necessarily mean it is correct. The representation of the device tree (as in the Linux kernel device tree) isn't quite accurate because you're missing the link of the host bridge to the parent PCIe controller. It also means that the representation of the kernel device tree doesn't match the DT representation.

Additionally, if you look at how PCI busses and devices are matched to their respective DT nodes, the code in drivers/pci/of.c provides a default implementation of pcibios_get_phb_of_node(), which matches the struct pci_bus up with the device_node of the parent device.

If we keep the current implementation that passes NULL as parent to the pci_scan_root_bus() function, then we'll have to provide a custom implementation of pcibios_get_phb_of_node() which has to go through similar hoops as the x86 version (see arch/x86/kernel/devicetree.c). That of course will not contribute to improving the current state of fragmentation in the PCI subsystem.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120615/0fe915be/attachment-0001.sig>

#45 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 41 lines · Thierry Reding
Quoted 35 lines · Stephen Warren
Quoted 2 lines · Thierry Reding
Quoted 1 line · Stephen Warren

On 06/14/2012 03:19 AM, Thierry Reding wrote:

...

Quoted 24 lines
Quoted 18 lines
Quoted 3 lines

#address-cells = <1>; #size-cells = <1>;

pci at 80000000 {

I'm still not convinced that using the address of the port's registers is the correct way to represent each port. The port index seems much more useful.

The main reason here is that there are a lot of registers that contain fields for each port - far more than the combination of this node's reg and ctrl-offset (which I assume is an address offset for just one example of this issue) properties can describe. The bit position and bit stride of these fields isn't necessarily the same in each register. Do we want a property like ctrl-offset for every single type of field in every single shared register that describes the location of the relevant data, or just a single "port ID" bit that can be applied to anything?

Quoted 5 lines

(Perhaps this isn't so obvious looking at the TRM since it doesn't document all registers, and I'm also looking at the Tegra30 documentation too, which might be more exposed to this - I haven't correlated all the documentation sources to be sure though)

Quoted 6 lines

I agree that maybe adding properties for each bit position or register offset may not work out too well. But I think it still makes sense to use the base address of the port's registers (see below). We could of course add some code to determine the index from the base address at initialization time and reuse the index where appropriate.

Quoted 4 lines

To me, working back from address to ID then using the ID to calculate some other addresses seems far more icky than just calculating all the addresses based off of one ID. But, I suppose this doesn't make a huge practical difference.

Quoted 6 lines

This really depends on the device vs. no device decision below. If we can make it work without needing an extra device for it, then using the index is certainly better. However, if we instantiate devices from the DT, then we have the address anyway and adding the index as a property would be redundant and error prone (what happens if somebody sets the index of the port at address 0x80000000 to 2?).

An additional problem with this is that we'd have to add the following to the pcie-controller node:

	#address-cells = <1>;
	#size-cells = <0>;

This will conflict with the "ranges" property, because suddenly we can no longer map the regions properly. Maybe Mitch can comment on whether this is possible or not?

To make it clearer what I'm talking about, here's the DT snippet again (with the compatible property removed from the pci@ nodes because they are no longer probed by a driver, the "simple-bus" removed from the pcie-controller node's compatible property removed and its #address- and #size-cells properties adjusted as described above).

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000>; /* extended configuration space */
		interrupts = <0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells = <1>;
		#size-cells = <0>;

		pci at 0 {
			reg = <2>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x81000000 0 0 0x80400000 0 0x00008000   /* I/O */
				  0x82000000 0 0 0x90000000 0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0 0xa0000000 0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x110>;
			nvidia,num-lanes = <2>;
		};

		pci at 1 {
			reg = <1>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x81000000 0 0 0x80408000 0 0x00008000   /* I/O */
				  0x82000000 0 0 0x98000000 0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0 0xa8000000 0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x118>;
			nvidia,num-lanes = <2>;
		};
	};

AIUI none of the ranges properties are valid anymore, because the bus represented by pcie-controller no longer reflects the truth, namely that it translates the CPU address space to the PCI address space.

Quoted 58 lines
Quoted 38 lines
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines

compatible = "nvidia,tegra20-pcie-port"; reg = <0x80000000 0x00001000>; status = "disabled";

#address-cells = <3>; #size-cells = <2>;

ranges = <0x81000000 0 0 0x80400000 0 0x00008000 /* I/O */
0x82000000 0 0 0x90000000 0 0x08000000 /* non-prefetchable
memory */ 0xc2000000 0 0 0xa0000000 0 0x08000000>; /* prefetchable memory */

Quoted 6 lines
Quoted 3 lines

The values here appear identical for both ports. Surely they should describe just the parts of the overall address space that have been assigned/delegated to the individual port/bridge?

They're not identical. Port 0 gets the first half and port 1 gets the second half of the ranges specified in the parent.

Oh right, I missed some 8s and 0s that looked the same!

Quoted 19 lines
Quoted 18 lines
Quoted 9 lines

While looking into some more code, trying to figure out how to hook this all up with the device tree I ran into a problem. I need to actually create a 'struct device' for each of the ports, so I added the "simple-bus" to the pcie-controller's "compatible" property. Furthermore, each PCI root port now becomes a platform_device, which are supported by a new tegra-pcie-port driver. I'm not sure if "port" is very common in PCI speek, so something like tegra-pcie-bridge (compatible = "nvidia,tegra20-pcie-bridge") may be more appropriate?

What is it that drives the need for each port to be a 'struct device'? The current driver supports 2 host ports, yet there's only a single struct device for it. Does the DT code assume a 1:1 mapping between struct device and DT node that represents the child bus? If so, perhaps it'd be better to rework that code to accept a DT node as a parameter and call it multiple times, rather than accept a struct device as a parameter and hence need multiple devices?

Quoted 8 lines
Quoted 5 lines

It's not so much the DT code, but rather the PCI core and ultimately the device model that requires it. Each port is basically a PCI host bridge that provides a root PCI bus and the device model is used to represent the hierachy of the busses. Providing just the DT node isn't going to be enough.

But the existing driver works without /any/ devices, let alone one per port.

That doesn't necessarily mean it is correct. The representation of the device tree (as in the Linux kernel device tree) isn't quite accurate because you're missing the link of the host bridge to the parent PCIe controller. It also means that the representation of the kernel device tree doesn't match the DT representation.

Additionally, if you look at how PCI busses and devices are matched to their respective DT nodes, the code in drivers/pci/of.c provides a default implementation of pcibios_get_phb_of_node(), which matches the struct pci_bus up with the device_node of the parent device.

Quoted 6 lines

If we keep the current implementation that passes NULL as parent to the pci_scan_root_bus() function, then we'll have to provide a custom implementation of pcibios_get_phb_of_node() which has to go through similar hoops as the x86 version (see arch/x86/kernel/devicetree.c). That of course will not contribute to improving the current state of fragmentation in the PCI subsystem.

I suppose this could work if we passed the 'struct device' of the pcie- controller node as the parent for all ports instead of requiring a separate device for each port. That way the pcie-controller would get to be a parent for two/three bridges on Tegra20/30.

I'll have a go at the implementation, but I'm busy with other stuff and it will probably be some time before I can get back on it.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120619/7b0150ac/attachment.sig>

#46 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 2 lines · Thierry Reding
Quoted 1 line · Thierry Reding

On Thu, Jun 14, 2012 at 01:50:56PM -0600, Stephen Warren wrote:

...

Quoted 77 lines
Quoted 11 lines
Quoted 4 lines

To me, working back from address to ID then using the ID to calculate some other addresses seems far more icky than just calculating all the addresses based off of one ID. But, I suppose this doesn't make a huge practical difference.

This really depends on the device vs. no device decision below. If we can make it work without needing an extra device for it, then using the index is certainly better. However, if we instantiate devices from the DT, then we have the address anyway and adding the index as a property would be redundant and error prone (what happens if somebody sets the index of the port at address 0x80000000 to 2?).

An additional problem with this is that we'd have to add the following to the pcie-controller node:

	#address-cells = <1>;
	#size-cells = <0>;

This will conflict with the "ranges" property, because suddenly we can no longer map the regions properly. Maybe Mitch can comment on whether this is possible or not?

To make it clearer what I'm talking about, here's the DT snippet again (with the compatible property removed from the pci@ nodes because they are no longer probed by a driver, the "simple-bus" removed from the pcie-controller node's compatible property removed and its #address- and #size-cells properties adjusted as described above).

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000>; /* extended configuration space */
		interrupts = <0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells = <1>;
		#size-cells = <0>;

		pci at 0 {
			reg = <2>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x81000000 0 0 0x80400000 0 0x00008000   /* I/O */
				  0x82000000 0 0 0x90000000 0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0 0xa0000000 0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x110>;
			nvidia,num-lanes = <2>;
		};

		pci at 1 {
			reg = <1>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x81000000 0 0 0x80408000 0 0x00008000   /* I/O */
				  0x82000000 0 0 0x98000000 0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0 0xa8000000 0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x118>;
			nvidia,num-lanes = <2>;
		};
	};
Quoted 3 lines

AIUI none of the ranges properties are valid anymore, because the bus represented by pcie-controller no longer reflects the truth, namely that it translates the CPU address space to the PCI address space.

Yes, I imagine that's a show-stopper for this approach.

#47 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

In reply to Thierry Reding
Quoted 114 lines · Thierry Reding
Quoted 41 lines · Thierry Reding
Quoted 35 lines · Stephen Warren
Quoted 2 lines · Thierry Reding
Quoted 1 line · Stephen Warren

On 06/14/2012 03:19 AM, Thierry Reding wrote:

...

Quoted 24 lines
Quoted 18 lines
Quoted 3 lines

#address-cells = <1>; #size-cells = <1>;

pci at 80000000 {

I'm still not convinced that using the address of the port's registers is the correct way to represent each port. The port index seems much more useful.

The main reason here is that there are a lot of registers that contain fields for each port - far more than the combination of this node's reg and ctrl-offset (which I assume is an address offset for just one example of this issue) properties can describe. The bit position and bit stride of these fields isn't necessarily the same in each register. Do we want a property like ctrl-offset for every single type of field in every single shared register that describes the location of the relevant data, or just a single "port ID" bit that can be applied to anything?

Quoted 5 lines

(Perhaps this isn't so obvious looking at the TRM since it doesn't document all registers, and I'm also looking at the Tegra30 documentation too, which might be more exposed to this - I haven't correlated all the documentation sources to be sure though)

Quoted 6 lines

I agree that maybe adding properties for each bit position or register offset may not work out too well. But I think it still makes sense to use the base address of the port's registers (see below). We could of course add some code to determine the index from the base address at initialization time and reuse the index where appropriate.

Quoted 4 lines

To me, working back from address to ID then using the ID to calculate some other addresses seems far more icky than just calculating all the addresses based off of one ID. But, I suppose this doesn't make a huge practical difference.

Quoted 6 lines

This really depends on the device vs. no device decision below. If we can make it work without needing an extra device for it, then using the index is certainly better. However, if we instantiate devices from the DT, then we have the address anyway and adding the index as a property would be redundant and error prone (what happens if somebody sets the index of the port at address 0x80000000 to 2?).

An additional problem with this is that we'd have to add the following to the pcie-controller node:

	#address-cells = <1>;
	#size-cells = <0>;

This will conflict with the "ranges" property, because suddenly we can no longer map the regions properly. Maybe Mitch can comment on whether this is possible or not?

To make it clearer what I'm talking about, here's the DT snippet again (with the compatible property removed from the pci@ nodes because they are no longer probed by a driver, the "simple-bus" removed from the pcie-controller node's compatible property removed and its #address- and #size-cells properties adjusted as described above).

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000>; /* extended configuration space */
		interrupts = <0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells = <1>;
		#size-cells = <0>;

		pci at 0 {
			reg = <2>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x81000000 0 0 0x80400000 0 0x00008000   /* I/O */
				  0x82000000 0 0 0x90000000 0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0 0xa0000000 0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x110>;
			nvidia,num-lanes = <2>;
		};

		pci at 1 {
			reg = <1>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x81000000 0 0 0x80408000 0 0x00008000   /* I/O */
				  0x82000000 0 0 0x98000000 0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0 0xa8000000 0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x118>;
			nvidia,num-lanes = <2>;
		};
	};
Quoted 4 lines

AIUI none of the ranges properties are valid anymore, because the bus represented by pcie-controller no longer reflects the truth, namely that it translates the CPU address space to the PCI address space.

I think you can use a small-integer port number as an address by defining the intermediate address space properly, and using appropriate ranges above and below. Here's a swag at how that would look.

I present three versions, using different choices for the intermediate address space encoding. The intermediate address space may seem somewhat artificial, in that it decouples the "linear pass through of ranges" between the lower PCI address space and the upper CPU address space. But in another sense, it accurately reflects that fact that the bus bridge "slices and dices" that linear address space into non-contiguous pieces.

Note that I'm also fixing a problem that I neglected to mention earlier
- namely the fact that config space is part of the child PCI address space so it must be passed through.

Version A - 3 address cells:  In this version, the intermediate address 
space has 3 cells:  port#, address type, offset.  Address type is

0 : root port
1 : config space
2 : extended config space
3 : I/O
4 : non-prefetchable memory
5 : prefetchable memory.

The third cell "offset" is necessary so that the size field has a number space that can include it.

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200>; /* extended configuration space */
		interrupts = <0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0 0 0  0x80000000 0x00001000   /* Root port 0 */
			  0 1 0  0x80004000 0x00080000   /* Port 0 config space */
			  0 2 0  0x80104000 0x00080000   /* Port 0 ext config space *
			  0 3 0  0x80400000 0x00008000   /* Port 0 downstream I/O */
			  0 4 0  0x90000000 0x08000000   /* Port 0 non-prefetchable memory */
			  0 5 0  0xa0000000 0x08000000   /* Port 0 prefetchable memory */

			  1 0 0  0x80001000 0x00001000   /* Root port 1 */
			  1 1 0  0x80004000 0x00080000   /* Port 1 config space */
			  1 2 0  0x80184000 0x00080000   /* Port 1 ext config space */
			  1 3 0  0x80408000 0x00010000   /* Port 1 downstream I/O */
			  1 4 0  0x98000000 0x08000000   /* Port 1 non-prefetchable memory */
			  1 5 0  0xa0000000 0x08000000>; /* Port 1 prefetchable memory */

		#address-cells = <3>;
		#size-cells = <1>;

		pci at 0 {
			reg = <0 0 0 0x1000>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x80000000 0 0  0 1 0  0 0x00080000   /* config */
				  0x90000000 0 0  0 2 0  0 0x00080000   /* extended config */
				  0x81000000 0 0  0 3 0  0 0x00008000   /* I/O */
				  0x82000000 0 0  0 4 0  0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0  0 5 0  0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x110>;
			nvidia,num-lanes = <2>;
		};


		pci at 1 {
			reg = <1 0 0 0x1000>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x80000000 0 0  1 1 0  0 0x00080000   /* config */
				  0x90000000 0 0  1 2 0  0 0x00080000   /* extended config */
				  0x81000000 0 0  1 3 0  0 0x00008000   /* I/O */
				  0x82000000 0 0  1 4 0  0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0  1 5 0  0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x118>;
			nvidia,num-lanes = <2>;
		};
Version B - 2 address cells:  In this first version, the intermediate
address space has 2 cells:  port#, offset.  The address type (I/O, mem,
etc) is the high digit of in the offset:
    Offset 0....... : Root port
    Offset 1....... : config
    Offset 2....... : extended config
    Offset 3....... : I/O
    Offset 4....... : non-prefetchable memory
    Offset 5....... : prefetchable memory.

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200>; /* AFI registers */

		interrupts = <0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0 0x00000000  0x80000000 0x00001000   /* Root port 0 */
			  0 0x10000000  0x80004000 0x00080000   /* Port 0 config */
			  0 0x20000000  0x80104000 0x00080000	/* Port 0 ext config */
			  0 0x30000000  0x80400000 0x00008000   /* Port 0 downstream I/O */
			  0 0x40000000  0x90000000 0x08000000   /* Port 0 non-prefetchable memory */
			  0 0x50000000  0xa0000000 0x08000000   /* Port 0 prefetchable memory */

			  1 0x00000000  0x80001000 0x00001000   /* Root port 1 */
			  1 0x10000000  0x80084000 0x00080000   /* Port 1 config */
			  1 0x20000000  0x80184000 0x00080000	/* Port 1 ext config */
			  1 0x30000000  0x80408000 0x00010000   /* Port 1 downstream I/O */
			  1 0x40000000  0x98000000 0x08000000   /* Port 1 non-prefetchable memory */
			  1 0x50000000  0xa0000000 0x08000000>; /* Port 1 prefetchable memory */

		#address-cells = <2>;
		#size-cells = <1>;

		pci at 0 {
			reg = <0 0 0x1000>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x80000000 0 0  0 0x10000000  0 0x00080000   /* config */
				  0x90000000 0 0  0 0x20000000  0 0x00080000   /* ext config */
				  0x81000000 0 0  0 0x30000000  0 0x00008000   /* I/O */
				  0x82000000 0 0  0 0x40000000  0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0  0 0x50000000  0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x110>;
			nvidia,num-lanes = <2>;
		};


		pci at 1 {
			reg = <1 0 0x1000>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x80000000 0 0  1 0x10000000  0 0x00080000   /* config */
				  0x90000000 0 0  1 0x20000000  0 0x00080000   /* ext config */
				  0x81000000 0 0  1 0x30000000  0 0x00008000   /* I/O */
				  0x82000000 0 0  1 0x40000000  0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0  1 0x50000000  0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x118>;
			nvidia,num-lanes = <2>;
		};

Version C - 2 address cells, 0 size cells (!) : In this version we hide the size component in the intermediate space. I don't know if that will actually work, but my guess is that it probably would. The intermediate address space is like version A with the omission of the offset field. The intermediate address just specifies the port number and the address type.

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200>; /* AFI registers */
		interrupts = <0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0 0  0x80000000   /* Root port 0 */
			  0 1  0x80004000   /* Port 0 config */
			  0 2  0x80104000   /* Port 0 ext config */
			  0 3  0x80400000   /* Port 0 downstream I/O */
			  0 4  0x90000000   /* Port 0 non-prefetchable memory */
			  0 5  0xa0000000   /* Port 0 prefetchable memory */

			  1 0  0x80001000   /* Root port 1 */
			  1 1  0x80084000   /* Port 1 config */
			  1 2  0x80184000   /* Port 1 ext config */
			  1 3  0x80408000   /* Port 1 downstream I/O */
			  1 4  0x98000000   /* Port 1 non-prefetchable memory */
			  1 5  0xa0000000>; /* Port 1 prefetchable memory */

		#address-cells = <2>;
		#size-cells = <0>;

		pci at 0 {
			reg = <0 0>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x80000000 0 0  0 1  0 0x00080000   /* config */
				  0x90000000 0 0  0 2  0 0x00080000   /* ext config */
				  0x81000000 0 0  0 3  0 0x00008000   /* I/O */
				  0x82000000 0 0  0 4  0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0  0 5  0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x110>;
			nvidia,num-lanes = <2>;
		};


		pci at 1 {
			reg = <1 0>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x80000000 0 0  1 1  0 0x00080000   /* config */
				  0x90000000 0 0  1 2  0 0x00080000   /* ext config */
				  0x81000000 0 0  1 3  0 0x00008000   /* I/O */
				  0x82000000 0 0  1 4  0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0  1 5  0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x118>;
			nvidia,num-lanes = <2>;
		};

In version C, you might even be able to include the ctrl register offset as a second entry in the reg property.

#48 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 142 lines · Mitch Bradley
Quoted 119 lines · Thierry Reding
Quoted 41 lines · Thierry Reding
Quoted 35 lines · Stephen Warren
Quoted 2 lines · Thierry Reding
Quoted 1 line · Stephen Warren

On 06/14/2012 03:19 AM, Thierry Reding wrote:

...

Quoted 24 lines
Quoted 18 lines
Quoted 3 lines

#address-cells = <1>; #size-cells = <1>;

pci at 80000000 {

I'm still not convinced that using the address of the port's registers is the correct way to represent each port. The port index seems much more useful.

The main reason here is that there are a lot of registers that contain fields for each port - far more than the combination of this node's reg and ctrl-offset (which I assume is an address offset for just one example of this issue) properties can describe. The bit position and bit stride of these fields isn't necessarily the same in each register. Do we want a property like ctrl-offset for every single type of field in every single shared register that describes the location of the relevant data, or just a single "port ID" bit that can be applied to anything?

Quoted 5 lines

(Perhaps this isn't so obvious looking at the TRM since it doesn't document all registers, and I'm also looking at the Tegra30 documentation too, which might be more exposed to this - I haven't correlated all the documentation sources to be sure though)

Quoted 6 lines

I agree that maybe adding properties for each bit position or register offset may not work out too well. But I think it still makes sense to use the base address of the port's registers (see below). We could of course add some code to determine the index from the base address at initialization time and reuse the index where appropriate.

Quoted 4 lines

To me, working back from address to ID then using the ID to calculate some other addresses seems far more icky than just calculating all the addresses based off of one ID. But, I suppose this doesn't make a huge practical difference.

Quoted 10 lines

This really depends on the device vs. no device decision below. If we can
make it work without needing an extra device for it, then using the index
is certainly better. However, if we instantiate devices from the DT, then
we have the address anyway and adding the index as a property would be redundant and error prone (what happens if somebody sets the index of the
port at address 0x80000000 to 2?).

An additional problem with this is that we'd have to add the following to the pcie-controller node:

    #address-cells = <1>;
    #size-cells = <0>;

This will conflict with the "ranges" property, because suddenly we can no longer map the regions properly. Maybe Mitch can comment on whether this is possible or not?

To make it clearer what I'm talking about, here's the DT snippet again (with the compatible property removed from the pci@ nodes because they are no longer probed by a driver, the "simple-bus" removed from the pcie-controller node's compatible property removed and its #address- and #size-cells properties adjusted as described above).

    pcie-controller {
        compatible = "nvidia,tegra20-pcie";
        reg = <0x80003000 0x00000800   /* PADS registers */
               0x80003800 0x00000200   /* AFI registers */
               0x80004000 0x00100000   /* configuration space */
               0x80104000 0x00100000>; /* extended configuration space */
        interrupts = <0 98 0x04   /* controller interrupt */
                  0 99 0x04>; /* MSI interrupt */
        status = "disabled";

        ranges = <0x80000000 0x80000000 0x00002000   /* 2 root ports */
              0x80400000 0x80400000 0x00010000   /* downstream I/O */
              0x90000000 0x90000000 0x10000000   /* non-prefetchable
memory */
              0xa0000000 0xa0000000 0x10000000>; /* prefetchable

memory */

        #address-cells = <1>;
        #size-cells = <0>;

        pci at 0 {
            reg = <2>;
            status = "disabled";

            #address-cells = <3>;
            #size-cells = <2>;

            ranges = <0x81000000 0 0 0x80400000 0 0x00008000   /* I/O */
                  0x82000000 0 0 0x90000000 0 0x08000000   /*
non-prefetchable memory */
                  0xc2000000 0 0 0xa0000000 0 0x08000000>; /*

prefetchable memory */

            nvidia,ctrl-offset = <0x110>;
            nvidia,num-lanes = <2>;
        };

        pci at 1 {
            reg = <1>;
            status = "disabled";

            #address-cells = <3>;
            #size-cells = <2>;

            ranges = <0x81000000 0 0 0x80408000 0 0x00008000   /* I/O */
                  0x82000000 0 0 0x98000000 0 0x08000000   /*
non-prefetchable memory */
                  0xc2000000 0 0 0xa8000000 0 0x08000000>; /*

prefetchable memory */

Quoted 9 lines
            nvidia,ctrl-offset = <0x118>;
            nvidia,num-lanes = <2>;
        };
    };

AIUI none of the ranges properties are valid anymore, because the bus represented by pcie-controller no longer reflects the truth, namely that it translates the CPU address space to the PCI address space.

I think you can use a small-integer port number as an address by defining the intermediate address space properly, and using appropriate ranges above and below. Here's a swag at how that would look.

I present three versions, using different choices for the intermediate address space encoding. The intermediate address space may seem somewhat artificial, in that it decouples the "linear pass through of ranges" between the lower PCI address space and the upper CPU address space. But in another sense, it accurately reflects that fact that the bus bridge "slices and dices" that linear address space into non-contiguous pieces.

Quoted 3 lines

Note that I'm also fixing a problem that I neglected to mention earlier
- namely the fact that config space is part of the child PCI address space so it must be passed through.

Impressive. I do tend to like these ideas...

Quoted 2 lines
Version A - 3 address cells:  In this version, the intermediate address
space has 3 cells:  port#, address type, offset.  Address type is

I think I personally tend to prefer this option; I like that everything is explicit and nicely separated.

Quoted 9 lines

0 : root port
1 : config space
2 : extended config space
3 : I/O
4 : non-prefetchable memory
5 : prefetchable memory.

The third cell "offset" is necessary so that the size field has a number space that can include it.

Can you expand on that sentence a bit more; I don't quite understand that aspect. Thanks.

#49 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 9 lines · Stephen Warren

On 06/19/2012 03:31 PM, Mitch Bradley wrote:
...

The third cell "offset" is necessary so that the size field has a number space that can include it.

Can you expand on that sentence a bit more; I don't quite understand that aspect. Thanks.

The meaning of "size"(in the context of "reg" which is phys,size) is "the device occupies a
contiguous sequence of addresses beginning at phys and continuing to phys+size-1". The
implicit addition occurs on the last #size-cells cells of the phys.

Suppose you have 2-cell phys where the values for different devices are <0 0>, <0 1>, <0 2>, <1 0>, <1 1>,
<1 2>. The first number is the port number and the second is address space type. It doesn't make
sense to say that size is 0x8000, because that would imply that the device extends from, say,
<1 2> to <1 0x8001>.

I'm not sure this is written down anywhere as explicitly as above, but it is certainly implicit
in the way that ranges properties work, and it is certainly part of the mental model that
was in my head when I developed the device tree addressing scheme.

#50 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 8 lines · Mitch Bradley
Quoted 7 lines · Stephen Warren

On 06/19/2012 03:31 PM, Mitch Bradley wrote:
...

The third cell "offset" is necessary so that the size field has a number space that can include it.

Quoted 8 lines
Quoted 2 lines

Can you expand on that sentence a bit more; I don't quite understand that aspect. Thanks.

The meaning of "size"(in the context of "reg" which is phys,size) is "the device occupies a
contiguous sequence of addresses beginning at phys and continuing to phys+size-1". The
implicit addition occurs on the last #size-cells cells of the phys.

Ah right of course - that makes perfect sense. Thanks.

#51 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

In reply to Mitch Bradley
Quoted 11 lines · Mitch Bradley
Version A - 3 address cells:  In this version, the intermediate address 
space has 3 cells:  port#, address type, offset.  Address type is

0 : root port
1 : config space
2 : extended config space
3 : I/O
4 : non-prefetchable memory
5 : prefetchable memory.

The third cell "offset" is necessary so that the size field has a number space that can include it.

I agree with Stephen that this is a clever way to encode all the address spaces, very nice!

Quoted 9 lines
Version B - 2 address cells:  In this first version, the intermediate
address space has 2 cells:  port#, offset.  The address type (I/O, mem,
etc) is the high digit of in the offset:
    Offset 0....... : Root port
    Offset 1....... : config
    Offset 2....... : extended config
    Offset 3....... : I/O
    Offset 4....... : non-prefetchable memory
    Offset 5....... : prefetchable memory.

This is similar to how the PCI binding works internally, but I find that a bit confusing as well, so given those two choices, I'd prefer the first one.

Quoted 4 lines

Version C - 2 address cells, 0 size cells (!) : In this version we hide the size component in the intermediate space. I don't know if that will actually work, but my guess is that it probably would. The intermediate address space is like version A with the omission of the offset field. The intermediate address just specifies the port number and the address type.

My guess is that it doesn't work with the current Linux code that transforms the addresses. I've just recently seen the code complain about any platform device whose parent has #size-cells=0.

Arnd

#52 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 27 lines · Arnd Bergmann
Quoted 11 lines · Mitch Bradley
Version A - 3 address cells:  In this version, the intermediate address
space has 3 cells:  port#, address type, offset.  Address type is

0 : root port
1 : config space
2 : extended config space
3 : I/O
4 : non-prefetchable memory
5 : prefetchable memory.

The third cell "offset" is necessary so that the size field has a number space that can include it.

I agree with Stephen that this is a clever way to encode all the address spaces, very nice!

Quoted 9 lines
Version B - 2 address cells:  In this first version, the intermediate
address space has 2 cells:  port#, offset.  The address type (I/O, mem,
etc) is the high digit of in the offset:
     Offset 0....... : Root port
     Offset 1....... : config
     Offset 2....... : extended config
     Offset 3....... : I/O
     Offset 4....... : non-prefetchable memory
     Offset 5....... : prefetchable memory.
Quoted 3 lines

This is similar to how the PCI binding works internally, but I find that a bit confusing as well, so given those two choices, I'd prefer the first one.

Yeah, version A is my preference too. It's straightforward and clear. I did the other two
versions mostly to explore the possibility space.

Quoted 13 lines
Quoted 6 lines

Version C - 2 address cells, 0 size cells (!) : In this version we hide the size component in the intermediate space. I don't know if that will actually work, but my guess is that it probably would. The intermediate address space is like version A with the omission of the offset field. The intermediate address just specifies the port number and the address type.

My guess is that it doesn't work with the current Linux code that transforms the addresses. I've just recently seen the code complain about any platform device whose parent has #size-cells=0.

Arnd

#53 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

In reply to Mitch Bradley
Quoted 133 lines · Mitch Bradley
Quoted 114 lines · Thierry Reding
Quoted 41 lines · Thierry Reding
Quoted 35 lines · Stephen Warren
Quoted 2 lines · Thierry Reding
Quoted 1 line · Stephen Warren

On 06/14/2012 03:19 AM, Thierry Reding wrote:

...

Quoted 24 lines
Quoted 18 lines
Quoted 3 lines

#address-cells = <1>; #size-cells = <1>;

pci at 80000000 {

I'm still not convinced that using the address of the port's registers is the correct way to represent each port. The port index seems much more useful.

The main reason here is that there are a lot of registers that contain fields for each port - far more than the combination of this node's reg and ctrl-offset (which I assume is an address offset for just one example of this issue) properties can describe. The bit position and bit stride of these fields isn't necessarily the same in each register. Do we want a property like ctrl-offset for every single type of field in every single shared register that describes the location of the relevant data, or just a single "port ID" bit that can be applied to anything?

Quoted 5 lines

(Perhaps this isn't so obvious looking at the TRM since it doesn't document all registers, and I'm also looking at the Tegra30 documentation too, which might be more exposed to this - I haven't correlated all the documentation sources to be sure though)

Quoted 6 lines

I agree that maybe adding properties for each bit position or register offset may not work out too well. But I think it still makes sense to use the base address of the port's registers (see below). We could of course add some code to determine the index from the base address at initialization time and reuse the index where appropriate.

Quoted 4 lines

To me, working back from address to ID then using the ID to calculate some other addresses seems far more icky than just calculating all the addresses based off of one ID. But, I suppose this doesn't make a huge practical difference.

Quoted 6 lines

This really depends on the device vs. no device decision below. If we can make it work without needing an extra device for it, then using the index is certainly better. However, if we instantiate devices from the DT, then we have the address anyway and adding the index as a property would be redundant and error prone (what happens if somebody sets the index of the port at address 0x80000000 to 2?).

An additional problem with this is that we'd have to add the following to the pcie-controller node:

	#address-cells = <1>;
	#size-cells = <0>;

This will conflict with the "ranges" property, because suddenly we can no longer map the regions properly. Maybe Mitch can comment on whether this is possible or not?

To make it clearer what I'm talking about, here's the DT snippet again (with the compatible property removed from the pci@ nodes because they are no longer probed by a driver, the "simple-bus" removed from the pcie-controller node's compatible property removed and its #address- and #size-cells properties adjusted as described above).

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000>; /* extended configuration space */
		interrupts = <0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells = <1>;
		#size-cells = <0>;

		pci at 0 {
			reg = <2>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x81000000 0 0 0x80400000 0 0x00008000   /* I/O */
				  0x82000000 0 0 0x90000000 0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0 0xa0000000 0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x110>;
			nvidia,num-lanes = <2>;
		};

		pci at 1 {
			reg = <1>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x81000000 0 0 0x80408000 0 0x00008000   /* I/O */
				  0x82000000 0 0 0x98000000 0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0 0xa8000000 0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x118>;
			nvidia,num-lanes = <2>;
		};
	};
Quoted 4 lines

AIUI none of the ranges properties are valid anymore, because the bus represented by pcie-controller no longer reflects the truth, namely that it translates the CPU address space to the PCI address space.

I think you can use a small-integer port number as an address by defining the intermediate address space properly, and using appropriate ranges above and below. Here's a swag at how that would look.

I present three versions, using different choices for the intermediate address space encoding. The intermediate address space may seem somewhat artificial, in that it decouples the "linear pass through of ranges" between the lower PCI address space and the upper CPU address space. But in another sense, it accurately reflects that fact that the bus bridge "slices and dices" that linear address space into non-contiguous pieces.

Quoted 3 lines

Note that I'm also fixing a problem that I neglected to mention earlier - namely the fact that config space is part of the child PCI address space so it must be passed through.

This doesn't quite match how the Tegra PCIe controller works. Basically, every access to a device's (extended) configuration space goes through a single region of memory-mapped registers, independent of which port is the parent of the device.

Is it okay to pass both configuration spaces via the ranges property but still list them in the reg property of the controller?

Quoted 64 lines
Version A - 3 address cells:  In this version, the intermediate
address space has 3 cells:  port#, address type, offset.  Address

type is
0 : root port
1 : config space
2 : extended config space
3 : I/O
4 : non-prefetchable memory
5 : prefetchable memory.

The third cell "offset" is necessary so that the size field has a number space that can include it.

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200>; /* extended configuration space */
		interrupts = <0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0 0 0  0x80000000 0x00001000   /* Root port 0 */
			  0 1 0  0x80004000 0x00080000   /* Port 0 config space */
			  0 2 0  0x80104000 0x00080000   /* Port 0 ext config space *
			  0 3 0  0x80400000 0x00008000   /* Port 0 downstream I/O */
			  0 4 0  0x90000000 0x08000000   /* Port 0 non-prefetchable memory */
			  0 5 0  0xa0000000 0x08000000   /* Port 0 prefetchable memory */

			  1 0 0  0x80001000 0x00001000   /* Root port 1 */
			  1 1 0  0x80004000 0x00080000   /* Port 1 config space */
			  1 2 0  0x80184000 0x00080000   /* Port 1 ext config space */
			  1 3 0  0x80408000 0x00010000   /* Port 1 downstream I/O */
			  1 4 0  0x98000000 0x08000000   /* Port 1 non-prefetchable memory */
			  1 5 0  0xa0000000 0x08000000>; /* Port 1 prefetchable memory */

		#address-cells = <3>;
		#size-cells = <1>;

		pci at 0 {
			reg = <0 0 0 0x1000>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x80000000 0 0  0 1 0  0 0x00080000   /* config */
				  0x90000000 0 0  0 2 0  0 0x00080000   /* extended config */
				  0x81000000 0 0  0 3 0  0 0x00008000   /* I/O */
				  0x82000000 0 0  0 4 0  0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0  0 5 0  0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x110>;
			nvidia,num-lanes = <2>;
		};


		pci at 1 {
			reg = <1 0 0 0x1000>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x80000000 0 0  1 1 0  0 0x00080000   /* config */
Quoted 8 lines
				  0x90000000 0 0  1 2 0  0 0x00080000   /* extended config */
				  0x81000000 0 0  1 3 0  0 0x00008000   /* I/O */
				  0x82000000 0 0  1 4 0  0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0  1 5 0  0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x118>;
			nvidia,num-lanes = <2>;
		};

Everybody seems to be happy with this approach, so I'll give it a shot. There is one thing I'm still unsure about, though. What if somebody uses the above scheme and maps the registers to the wrong port. The same goes for the nvidia,ctrl-offset property. It needs to match the register offset because they are directly related. I suppose we could leave that property away and look up the register via the port index (which, as Stephen already said, we'll have to do in other places anyway, unless we list all bit positions in the DT).

Can we safely ignore such issues and assume the device tree to always be right? Should we just not care if somebody uses it wrongly?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120621/1025714d/attachment.sig>

maintainer
#54 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 71 lines · Thierry Reding
Quoted 69 lines · Mitch Bradley

Version A - 3 address cells: ?In this version, the intermediate address space has 3 cells: ?port#, address type, offset. ?Address type is
? 0 : root port
? 1 : config space
? 2 : extended config space
? 3 : I/O
? 4 : non-prefetchable memory
? 5 : prefetchable memory.

The third cell "offset" is necessary so that the size field has a number space that can include it.

? ? ? pcie-controller {
? ? ? ? ? ? ? compatible = "nvidia,tegra20-pcie";
? ? ? ? ? ? ? reg = <0x80003000 0x00000800 ? /* PADS registers */ ? ? ? ? ? ? ? ? ? ? ?0x80003800 0x00000200>; /* extended configuration space */ ? ? ? ? ? ? ? interrupts = <0 98 0x04 ? /* controller interrupt */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0 99 0x04>; /* MSI interrupt */
? ? ? ? ? ? ? status = "disabled";

? ? ? ? ? ? ? ranges = <0 0 0 ?0x80000000 0x00001000 ? /* Root port 0 */
? ? ? ? ? ? ? ? ? ? ? ? 0 1 0 ?0x80004000 0x00080000 ? /* Port 0 config space */ ? ? ? ? ? ? ? ? ? ? ? ? 0 2 0 ?0x80104000 0x00080000 ? /* Port 0 ext config space * ? ? ? ? ? ? ? ? ? ? ? ? 0 3 0 ?0x80400000 0x00008000 ? /* Port 0 downstream I/O */ ? ? ? ? ? ? ? ? ? ? ? ? 0 4 0 ?0x90000000 0x08000000 ? /* Port 0 non-prefetchable memory */ ? ? ? ? ? ? ? ? ? ? ? ? 0 5 0 ?0xa0000000 0x08000000 ? /* Port 0 prefetchable memory */

? ? ? ? ? ? ? ? ? ? ? ? 1 0 0 ?0x80001000 0x00001000 ? /* Root port 1 */
? ? ? ? ? ? ? ? ? ? ? ? 1 1 0 ?0x80004000 0x00080000 ? /* Port 1 config space */ ? ? ? ? ? ? ? ? ? ? ? ? 1 2 0 ?0x80184000 0x00080000 ? /* Port 1 ext config space */ ? ? ? ? ? ? ? ? ? ? ? ? 1 3 0 ?0x80408000 0x00010000 ? /* Port 1 downstream I/O */ ? ? ? ? ? ? ? ? ? ? ? ? 1 4 0 ?0x98000000 0x08000000 ? /* Port 1 non-prefetchable memory */ ? ? ? ? ? ? ? ? ? ? ? ? 1 5 0 ?0xa0000000 0x08000000>; /* Port 1 prefetchable memory */

? ? ? ? ? ? ? #address-cells = <3>;
? ? ? ? ? ? ? #size-cells = <1>;

? ? ? ? ? ? ? pci at 0 {
? ? ? ? ? ? ? ? ? ? ? reg = <0 0 0 0x1000>;
? ? ? ? ? ? ? ? ? ? ? status = "disabled";

? ? ? ? ? ? ? ? ? ? ? #address-cells = <3>;
? ? ? ? ? ? ? ? ? ? ? #size-cells = <2>;

? ? ? ? ? ? ? ? ? ? ? ranges = <0x80000000 0 0 ?0 1 0 ?0 0x00080000 ? /* config */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x90000000 0 0 ?0 2 0 ?0 0x00080000 ? /* extended config */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x81000000 0 0 ?0 3 0 ?0 0x00008000 ? /* I/O */
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x82000000 0 0 ?0 4 0 ?0 0x08000000 ? /* non-prefetchable memory */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0xc2000000 0 0 ?0 5 0 ?0 0x08000000>; /* prefetchable memory */

? ? ? ? ? ? ? ? ? ? ? nvidia,ctrl-offset = <0x110>; ? ? ? ? ? ? ? ? ? ? ? nvidia,num-lanes = <2>; ? ? ? ? ? ? ? };

? ? ? ? ? ? ? pci at 1 {
? ? ? ? ? ? ? ? ? ? ? reg = <1 0 0 0x1000>;
? ? ? ? ? ? ? ? ? ? ? status = "disabled";

? ? ? ? ? ? ? ? ? ? ? #address-cells = <3>;
? ? ? ? ? ? ? ? ? ? ? #size-cells = <2>;

? ? ? ? ? ? ? ? ? ? ? ranges = <0x80000000 0 0 ?1 1 0 ?0 0x00080000 ? /* config */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x90000000 0 0 ?1 2 0 ?0 0x00080000 ? /* extended config */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x81000000 0 0 ?1 3 0 ?0 0x00008000 ? /* I/O */
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x82000000 0 0 ?1 4 0 ?0 0x08000000 ? /* non-prefetchable memory */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0xc2000000 0 0 ?1 5 0 ?0 0x08000000>; /* prefetchable memory */

Quoted 3 lines
Quoted 3 lines

? ? ? ? ? ? ? ? ? ? ? nvidia,ctrl-offset = <0x118>; ? ? ? ? ? ? ? ? ? ? ? nvidia,num-lanes = <2>; ? ? ? ? ? ? ? };

I'm not familiar with device tree, so pardon me if these are stupid questions. These seem to be describing PCI host bridges. I assume some of these ranges describe MMIO, prefetchable MMIO, and I/O port apertures that the bridge forwards to the PCI bus.

Is there provision for any address offset applied by the bridge when it forwards downstream? (Maybe these bridges don't apply any offset?)
"0xa0000000 0x08000000" appears for both ports 0 and 1 prefetchable
memory; I don't know if that's an error, an indication that each bridge applies a different offset, or that both bridges forward the same aperture (I hope not the latter, because Linux can't really deal with that).

Is the bus number aperture included somewhere? How do we know what bus numbers are available for allocation under each bridge?

I see mention of config space. Is some of that referring to the ECAM as in 7.2.2 of the PCIe spec v3.0 (what we refer to as MMCONFIG on x86)?

#55 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 73 lines · Bjorn Helgaas
Quoted 71 lines · Thierry Reding
Quoted 69 lines · Mitch Bradley

Version A - 3 address cells: ?In this version, the intermediate address space has 3 cells: ?port#, address type, offset. ?Address type is
? 0 : root port
? 1 : config space
? 2 : extended config space
? 3 : I/O
? 4 : non-prefetchable memory
? 5 : prefetchable memory.

The third cell "offset" is necessary so that the size field has a number space that can include it.

? ? ? pcie-controller {
? ? ? ? ? ? ? compatible = "nvidia,tegra20-pcie";
? ? ? ? ? ? ? reg = <0x80003000 0x00000800 ? /* PADS registers */ ? ? ? ? ? ? ? ? ? ? ?0x80003800 0x00000200>; /* extended configuration space */ ? ? ? ? ? ? ? interrupts = <0 98 0x04 ? /* controller interrupt */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0 99 0x04>; /* MSI interrupt */
? ? ? ? ? ? ? status = "disabled";

? ? ? ? ? ? ? ranges = <0 0 0 ?0x80000000 0x00001000 ? /* Root port 0 */
? ? ? ? ? ? ? ? ? ? ? ? 0 1 0 ?0x80004000 0x00080000 ? /* Port 0 config space */ ? ? ? ? ? ? ? ? ? ? ? ? 0 2 0 ?0x80104000 0x00080000 ? /* Port 0 ext config space * ? ? ? ? ? ? ? ? ? ? ? ? 0 3 0 ?0x80400000 0x00008000 ? /* Port 0 downstream I/O */ ? ? ? ? ? ? ? ? ? ? ? ? 0 4 0 ?0x90000000 0x08000000 ? /* Port 0 non-prefetchable memory */ ? ? ? ? ? ? ? ? ? ? ? ? 0 5 0 ?0xa0000000 0x08000000 ? /* Port 0 prefetchable memory */

? ? ? ? ? ? ? ? ? ? ? ? 1 0 0 ?0x80001000 0x00001000 ? /* Root port 1 */
? ? ? ? ? ? ? ? ? ? ? ? 1 1 0 ?0x80004000 0x00080000 ? /* Port 1 config space */ ? ? ? ? ? ? ? ? ? ? ? ? 1 2 0 ?0x80184000 0x00080000 ? /* Port 1 ext config space */ ? ? ? ? ? ? ? ? ? ? ? ? 1 3 0 ?0x80408000 0x00010000 ? /* Port 1 downstream I/O */ ? ? ? ? ? ? ? ? ? ? ? ? 1 4 0 ?0x98000000 0x08000000 ? /* Port 1 non-prefetchable memory */ ? ? ? ? ? ? ? ? ? ? ? ? 1 5 0 ?0xa0000000 0x08000000>; /* Port 1 prefetchable memory */

? ? ? ? ? ? ? #address-cells = <3>;
? ? ? ? ? ? ? #size-cells = <1>;

? ? ? ? ? ? ? pci at 0 {
? ? ? ? ? ? ? ? ? ? ? reg = <0 0 0 0x1000>;
? ? ? ? ? ? ? ? ? ? ? status = "disabled";

? ? ? ? ? ? ? ? ? ? ? #address-cells = <3>;
? ? ? ? ? ? ? ? ? ? ? #size-cells = <2>;

? ? ? ? ? ? ? ? ? ? ? ranges = <0x80000000 0 0 ?0 1 0 ?0 0x00080000 ? /* config */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x90000000 0 0 ?0 2 0 ?0 0x00080000 ? /* extended config */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x81000000 0 0 ?0 3 0 ?0 0x00008000 ? /* I/O */
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x82000000 0 0 ?0 4 0 ?0 0x08000000 ? /* non-prefetchable memory */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0xc2000000 0 0 ?0 5 0 ?0 0x08000000>; /* prefetchable memory */

? ? ? ? ? ? ? ? ? ? ? nvidia,ctrl-offset = <0x110>; ? ? ? ? ? ? ? ? ? ? ? nvidia,num-lanes = <2>; ? ? ? ? ? ? ? };

? ? ? ? ? ? ? pci at 1 {
? ? ? ? ? ? ? ? ? ? ? reg = <1 0 0 0x1000>;
? ? ? ? ? ? ? ? ? ? ? status = "disabled";

? ? ? ? ? ? ? ? ? ? ? #address-cells = <3>;
? ? ? ? ? ? ? ? ? ? ? #size-cells = <2>;

? ? ? ? ? ? ? ? ? ? ? ranges = <0x80000000 0 0 ?1 1 0 ?0 0x00080000 ? /* config */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x90000000 0 0 ?1 2 0 ?0 0x00080000 ? /* extended config */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x81000000 0 0 ?1 3 0 ?0 0x00008000 ? /* I/O */
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x82000000 0 0 ?1 4 0 ?0 0x08000000 ? /* non-prefetchable memory */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0xc2000000 0 0 ?1 5 0 ?0 0x08000000>; /* prefetchable memory */

Quoted 6 lines
Quoted 3 lines
Quoted 3 lines

? ? ? ? ? ? ? ? ? ? ? nvidia,ctrl-offset = <0x118>; ? ? ? ? ? ? ? ? ? ? ? nvidia,num-lanes = <2>; ? ? ? ? ? ? ? };

I'm not familiar with device tree, so pardon me if these are stupid questions. These seem to be describing PCI host bridges.

Yes, correct.

Quoted 2 lines

I assume some of these ranges describe MMIO, prefetchable MMIO, and I/O port apertures that the bridge forwards to the PCI bus.

Yes.

Quoted 7 lines

Is there provision for any address offset applied by the bridge when it forwards downstream? (Maybe these bridges don't apply any offset?)
"0xa0000000 0x08000000" appears for both ports 0 and 1 prefetchable
memory; I don't know if that's an error, an indication that each bridge applies a different offset, or that both bridges forward the same aperture (I hope not the latter, because Linux can't really deal with that).

That seems to be a typo. It should have been 0xa8000000 in the second case. The PCIe controller has registers that are programmed with the aperture for the configuration and extended configuration spaces, as well as the downstream I/O, prefetchable and non-prefetchable memory regions.

The configuration spaces aren't actually forwarded by the bridges, but are handled only by the controller. The other apertures are programmed into the bridges using standard PCI registers.

Quoted 2 lines

Is the bus number aperture included somewhere? How do we know what bus numbers are available for allocation under each bridge?

Not yet. I don't think DT imposes a bus number allocation on PCI bridges. However the matching of DT nodes to PCI bridges is done based on the bus number. For that you provide a bus-ranges property which defines the bus aperture of the given PCI bridge. The DT matching code compares the first cell of this property with the primary bus number of the bridge.

This is in fact somewhat counter-productive because it requires you to hard-code the PCI hierarchy within the DT and you loose a lot of the probing functionality. This is not much of an issue for typical PCI endpoints (like network cards) but becomes a problem if you have a PCI endpoint that implements an I2C bus and you want to match I2C slaves on that bus to device nodes so that the kernel can parse and instantiate them properly. I guess in the latter cases hard-coding the PCI tree in DT is not actually a drawback, though.

Quoted 3 lines

I see mention of config space. Is some of that referring to the ECAM as in 7.2.2 of the PCIe spec v3.0 (what we refer to as MMCONFIG on x86)?

I only have access to the PCIe 2.0 specification, but it seems to contain the same 7.2.2 section. In fact it looks as though this particular controller indeed implements something similar to ECAM. The address mapping is a little different, though:

	A[(16 + n - 1):16]: bus number
	A[15:11]: device number
	A[10:8]: function number
	A[7:2]: register number
	A[1:0]: unused

That information comes directly from the driver and I have no access to the corresponding documentation. It seems like the extended configuration space is accessed using the same mapping but starting at a different base address.

But now that you mention it, maybe the driver code is buggy here, and the controller indeed implements ECAM. Furthermore it also seems like the current code doesn't work for the extended configuration space because while the correct offset into the extended configuration space is chosen, the access to registers is done using the same mapping as above, so instead of the 12 (10) bits required for the register number only 8 (6) are in fact used.

I wonder whether anyone's actually tested this.

Stephen: can you try to find out whether the Tegra PCIe controller indeed implements ECAM, or if this scheme is actually just a proprietary variant?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120622/e48a90b3/attachment.sig>

maintainer
#56 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 96 lines · Thierry Reding
Quoted 73 lines · Bjorn Helgaas
Quoted 71 lines · Thierry Reding
Quoted 69 lines · Mitch Bradley

Version A - 3 address cells: ?In this version, the intermediate address space has 3 cells: ?port#, address type, offset. ?Address type is
? 0 : root port
? 1 : config space
? 2 : extended config space
? 3 : I/O
? 4 : non-prefetchable memory
? 5 : prefetchable memory.

The third cell "offset" is necessary so that the size field has a number space that can include it.

? ? ? pcie-controller {
? ? ? ? ? ? ? compatible = "nvidia,tegra20-pcie";
? ? ? ? ? ? ? reg = <0x80003000 0x00000800 ? /* PADS registers */ ? ? ? ? ? ? ? ? ? ? ?0x80003800 0x00000200>; /* extended configuration space */ ? ? ? ? ? ? ? interrupts = <0 98 0x04 ? /* controller interrupt */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0 99 0x04>; /* MSI interrupt */
? ? ? ? ? ? ? status = "disabled";

? ? ? ? ? ? ? ranges = <0 0 0 ?0x80000000 0x00001000 ? /* Root port 0 */
? ? ? ? ? ? ? ? ? ? ? ? 0 1 0 ?0x80004000 0x00080000 ? /* Port 0 config space */ ? ? ? ? ? ? ? ? ? ? ? ? 0 2 0 ?0x80104000 0x00080000 ? /* Port 0 ext config space * ? ? ? ? ? ? ? ? ? ? ? ? 0 3 0 ?0x80400000 0x00008000 ? /* Port 0 downstream I/O */ ? ? ? ? ? ? ? ? ? ? ? ? 0 4 0 ?0x90000000 0x08000000 ? /* Port 0 non-prefetchable memory */ ? ? ? ? ? ? ? ? ? ? ? ? 0 5 0 ?0xa0000000 0x08000000 ? /* Port 0 prefetchable memory */

? ? ? ? ? ? ? ? ? ? ? ? 1 0 0 ?0x80001000 0x00001000 ? /* Root port 1 */
? ? ? ? ? ? ? ? ? ? ? ? 1 1 0 ?0x80004000 0x00080000 ? /* Port 1 config space */ ? ? ? ? ? ? ? ? ? ? ? ? 1 2 0 ?0x80184000 0x00080000 ? /* Port 1 ext config space */ ? ? ? ? ? ? ? ? ? ? ? ? 1 3 0 ?0x80408000 0x00010000 ? /* Port 1 downstream I/O */ ? ? ? ? ? ? ? ? ? ? ? ? 1 4 0 ?0x98000000 0x08000000 ? /* Port 1 non-prefetchable memory */ ? ? ? ? ? ? ? ? ? ? ? ? 1 5 0 ?0xa0000000 0x08000000>; /* Port 1 prefetchable memory */

? ? ? ? ? ? ? #address-cells = <3>;
? ? ? ? ? ? ? #size-cells = <1>;

? ? ? ? ? ? ? pci at 0 {
? ? ? ? ? ? ? ? ? ? ? reg = <0 0 0 0x1000>;
? ? ? ? ? ? ? ? ? ? ? status = "disabled";

? ? ? ? ? ? ? ? ? ? ? #address-cells = <3>;
? ? ? ? ? ? ? ? ? ? ? #size-cells = <2>;

? ? ? ? ? ? ? ? ? ? ? ranges = <0x80000000 0 0 ?0 1 0 ?0 0x00080000 ? /* config */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x90000000 0 0 ?0 2 0 ?0 0x00080000 ? /* extended config */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x81000000 0 0 ?0 3 0 ?0 0x00008000 ? /* I/O */
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x82000000 0 0 ?0 4 0 ?0 0x08000000 ? /* non-prefetchable memory */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0xc2000000 0 0 ?0 5 0 ?0 0x08000000>; /* prefetchable memory */

? ? ? ? ? ? ? ? ? ? ? nvidia,ctrl-offset = <0x110>; ? ? ? ? ? ? ? ? ? ? ? nvidia,num-lanes = <2>; ? ? ? ? ? ? ? };

? ? ? ? ? ? ? pci at 1 {
? ? ? ? ? ? ? ? ? ? ? reg = <1 0 0 0x1000>;
? ? ? ? ? ? ? ? ? ? ? status = "disabled";

? ? ? ? ? ? ? ? ? ? ? #address-cells = <3>;
? ? ? ? ? ? ? ? ? ? ? #size-cells = <2>;

? ? ? ? ? ? ? ? ? ? ? ranges = <0x80000000 0 0 ?1 1 0 ?0 0x00080000 ? /* config */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x90000000 0 0 ?1 2 0 ?0 0x00080000 ? /* extended config */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x81000000 0 0 ?1 3 0 ?0 0x00008000 ? /* I/O */
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x82000000 0 0 ?1 4 0 ?0 0x08000000 ? /* non-prefetchable memory */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0xc2000000 0 0 ?1 5 0 ?0 0x08000000>; /* prefetchable memory */

Quoted 6 lines
Quoted 3 lines
Quoted 3 lines

? ? ? ? ? ? ? ? ? ? ? nvidia,ctrl-offset = <0x118>; ? ? ? ? ? ? ? ? ? ? ? nvidia,num-lanes = <2>; ? ? ? ? ? ? ? };

I'm not familiar with device tree, so pardon me if these are stupid questions. ?These seem to be describing PCI host bridges.

Yes, correct.

Quoted 2 lines

I assume some of these ranges describe MMIO, prefetchable MMIO, and I/O port apertures that the bridge forwards to the PCI bus.

Yes.

Quoted 7 lines

Is there provision for any address offset applied by the bridge when it forwards downstream? ?(Maybe these bridges don't apply any offset?) ?"0xa0000000 0x08000000" appears for both ports 0 and 1 prefetchable memory; I don't know if that's an error, an indication that each bridge applies a different offset, or that both bridges forward the same aperture (I hope not the latter, because Linux can't really deal with that).

Quoted 8 lines

That seems to be a typo. It should have been 0xa8000000 in the second case. The PCIe controller has registers that are programmed with the aperture for the configuration and extended configuration spaces, as well as the downstream I/O, prefetchable and non-prefetchable memory regions.

The configuration spaces aren't actually forwarded by the bridges, but are handled only by the controller.

Right. The host bridge (controller) would convert memory accesses on the upstream side into PCI config accesses on its downstream PCI interface.

Quoted 2 lines

The other apertures are programmed
into the bridges using standard PCI registers.

If you're talking about programming host bridge apertures, there are no "standard PCI registers" to do that. The programming model of the host bridge itself is not part of the PCI spec. PCI-to-PCI bridge apertures *are* specified by the PCI Bridge spec, so those are standard.

Quoted 9 lines
Quoted 2 lines

Is the bus number aperture included somewhere? ?How do we know what bus numbers are available for allocation under each bridge?

Not yet. I don't think DT imposes a bus number allocation on PCI bridges. However the matching of DT nodes to PCI bridges is done based on the bus number. For that you provide a bus-ranges property which defines the bus aperture of the given PCI bridge. The DT matching code compares the first cell of this property with the primary bus number of the bridge.

I don't fully understand this, but I can tell you that things don't work very well if we don't know the aperture. We can make assumptions, like the root bus is 00, and then enumerate everything reachable from there. But then all we know is the largest bus number actually reachable from bus 00, which is usually smaller then the end of the aperture. We don't know how many unused bus numbers there are in the aperture, so we can't safely allocate any for hot-added devices.

Quoted 37 lines

This is in fact somewhat counter-productive because it requires you to hard-code the PCI hierarchy within the DT and you loose a lot of the probing functionality. This is not much of an issue for typical PCI endpoints (like network cards) but becomes a problem if you have a PCI endpoint that implements an I2C bus and you want to match I2C slaves on that bus to device nodes so that the kernel can parse and instantiate them properly. I guess in the latter cases hard-coding the PCI tree in DT is not actually a drawback, though.

Quoted 3 lines

I see mention of config space. ?Is some of that referring to the ECAM as in 7.2.2 of the PCIe spec v3.0 (what we refer to as MMCONFIG on x86)?

I only have access to the PCIe 2.0 specification, but it seems to contain the same 7.2.2 section. In fact it looks as though this particular controller indeed implements something similar to ECAM. The address mapping is a little different, though:

? ? ? ?A[(16 + n - 1):16]: bus number
? ? ? ?A[15:11]: device number
? ? ? ?A[10:8]: function number
? ? ? ?A[7:2]: register number
? ? ? ?A[1:0]: unused

That information comes directly from the driver and I have no access to the corresponding documentation. It seems like the extended configuration space is accessed using the same mapping but starting at a different base address.

But now that you mention it, maybe the driver code is buggy here, and the controller indeed implements ECAM. Furthermore it also seems like the current code doesn't work for the extended configuration space because while the correct offset into the extended configuration space is chosen, the access to registers is done using the same mapping as above, so instead of the 12 (10) bits required for the register number only 8 (6) are in fact used.

Quoted 5 lines

I wonder whether anyone's actually tested this.

Stephen: can you try to find out whether the Tegra PCIe controller indeed implements ECAM, or if this scheme is actually just a proprietary variant?

It'd be a real shame if they made up a proprietary scheme when ECAM seems to be required by the spec. I'm interested because the current MMCONFIG code seems unnecessarily x86-specific, and I expect every arch with PCIe would want to use ECAM, so maybe there's some chance for a generic implementation.

#57 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 111 lines · Bjorn Helgaas
Quoted 96 lines · Thierry Reding
Quoted 73 lines · Bjorn Helgaas
Quoted 71 lines · Thierry Reding
Quoted 69 lines · Mitch Bradley

Version A - 3 address cells: ?In this version, the intermediate address space has 3 cells: ?port#, address type, offset. ?Address type is
? 0 : root port
? 1 : config space
? 2 : extended config space
? 3 : I/O
? 4 : non-prefetchable memory
? 5 : prefetchable memory.

The third cell "offset" is necessary so that the size field has a number space that can include it.

? ? ? pcie-controller {
? ? ? ? ? ? ? compatible = "nvidia,tegra20-pcie";
? ? ? ? ? ? ? reg = <0x80003000 0x00000800 ? /* PADS registers */ ? ? ? ? ? ? ? ? ? ? ?0x80003800 0x00000200>; /* extended configuration space */ ? ? ? ? ? ? ? interrupts = <0 98 0x04 ? /* controller interrupt */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0 99 0x04>; /* MSI interrupt */
? ? ? ? ? ? ? status = "disabled";

? ? ? ? ? ? ? ranges = <0 0 0 ?0x80000000 0x00001000 ? /* Root port 0 */
? ? ? ? ? ? ? ? ? ? ? ? 0 1 0 ?0x80004000 0x00080000 ? /* Port 0 config space */ ? ? ? ? ? ? ? ? ? ? ? ? 0 2 0 ?0x80104000 0x00080000 ? /* Port 0 ext config space * ? ? ? ? ? ? ? ? ? ? ? ? 0 3 0 ?0x80400000 0x00008000 ? /* Port 0 downstream I/O */ ? ? ? ? ? ? ? ? ? ? ? ? 0 4 0 ?0x90000000 0x08000000 ? /* Port 0 non-prefetchable memory */ ? ? ? ? ? ? ? ? ? ? ? ? 0 5 0 ?0xa0000000 0x08000000 ? /* Port 0 prefetchable memory */

? ? ? ? ? ? ? ? ? ? ? ? 1 0 0 ?0x80001000 0x00001000 ? /* Root port 1 */
? ? ? ? ? ? ? ? ? ? ? ? 1 1 0 ?0x80004000 0x00080000 ? /* Port 1 config space */ ? ? ? ? ? ? ? ? ? ? ? ? 1 2 0 ?0x80184000 0x00080000 ? /* Port 1 ext config space */ ? ? ? ? ? ? ? ? ? ? ? ? 1 3 0 ?0x80408000 0x00010000 ? /* Port 1 downstream I/O */ ? ? ? ? ? ? ? ? ? ? ? ? 1 4 0 ?0x98000000 0x08000000 ? /* Port 1 non-prefetchable memory */ ? ? ? ? ? ? ? ? ? ? ? ? 1 5 0 ?0xa0000000 0x08000000>; /* Port 1 prefetchable memory */

? ? ? ? ? ? ? #address-cells = <3>;
? ? ? ? ? ? ? #size-cells = <1>;

? ? ? ? ? ? ? pci at 0 {
? ? ? ? ? ? ? ? ? ? ? reg = <0 0 0 0x1000>;
? ? ? ? ? ? ? ? ? ? ? status = "disabled";

? ? ? ? ? ? ? ? ? ? ? #address-cells = <3>;
? ? ? ? ? ? ? ? ? ? ? #size-cells = <2>;

? ? ? ? ? ? ? ? ? ? ? ranges = <0x80000000 0 0 ?0 1 0 ?0 0x00080000 ? /* config */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x90000000 0 0 ?0 2 0 ?0 0x00080000 ? /* extended config */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x81000000 0 0 ?0 3 0 ?0 0x00008000 ? /* I/O */
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x82000000 0 0 ?0 4 0 ?0 0x08000000 ? /* non-prefetchable memory */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0xc2000000 0 0 ?0 5 0 ?0 0x08000000>; /* prefetchable memory */

? ? ? ? ? ? ? ? ? ? ? nvidia,ctrl-offset = <0x110>; ? ? ? ? ? ? ? ? ? ? ? nvidia,num-lanes = <2>; ? ? ? ? ? ? ? };

? ? ? ? ? ? ? pci at 1 {
? ? ? ? ? ? ? ? ? ? ? reg = <1 0 0 0x1000>;
? ? ? ? ? ? ? ? ? ? ? status = "disabled";

? ? ? ? ? ? ? ? ? ? ? #address-cells = <3>;
? ? ? ? ? ? ? ? ? ? ? #size-cells = <2>;

? ? ? ? ? ? ? ? ? ? ? ranges = <0x80000000 0 0 ?1 1 0 ?0 0x00080000 ? /* config */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x90000000 0 0 ?1 2 0 ?0 0x00080000 ? /* extended config */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x81000000 0 0 ?1 3 0 ?0 0x00008000 ? /* I/O */
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x82000000 0 0 ?1 4 0 ?0 0x08000000 ? /* non-prefetchable memory */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0xc2000000 0 0 ?1 5 0 ?0 0x08000000>; /* prefetchable memory */

Quoted 6 lines
Quoted 3 lines
Quoted 3 lines

? ? ? ? ? ? ? ? ? ? ? nvidia,ctrl-offset = <0x118>; ? ? ? ? ? ? ? ? ? ? ? nvidia,num-lanes = <2>; ? ? ? ? ? ? ? };

I'm not familiar with device tree, so pardon me if these are stupid questions. ?These seem to be describing PCI host bridges.

Yes, correct.

Quoted 2 lines

I assume some of these ranges describe MMIO, prefetchable MMIO, and I/O port apertures that the bridge forwards to the PCI bus.

Yes.

Quoted 7 lines

Is there provision for any address offset applied by the bridge when it forwards downstream? ?(Maybe these bridges don't apply any offset?) ?"0xa0000000 0x08000000" appears for both ports 0 and 1 prefetchable memory; I don't know if that's an error, an indication that each bridge applies a different offset, or that both bridges forward the same aperture (I hope not the latter, because Linux can't really deal with that).

Quoted 8 lines

That seems to be a typo. It should have been 0xa8000000 in the second case. The PCIe controller has registers that are programmed with the aperture for the configuration and extended configuration spaces, as well as the downstream I/O, prefetchable and non-prefetchable memory regions.

The configuration spaces aren't actually forwarded by the bridges, but are handled only by the controller.

Right. The host bridge (controller) would convert memory accesses on the upstream side into PCI config accesses on its downstream PCI interface.

Quoted 8 lines
Quoted 2 lines

The other apertures are programmed
into the bridges using standard PCI registers.

If you're talking about programming host bridge apertures, there are no "standard PCI registers" to do that. The programming model of the host bridge itself is not part of the PCI spec. PCI-to-PCI bridge apertures *are* specified by the PCI Bridge spec, so those are standard.

Each of the root ports has a PCI-compatible set of configuration registers, so I guess what is meant is that the apertures a programmed according to the PCI bridge specification.

Quoted 10 lines
Quoted 9 lines
Quoted 2 lines

Is the bus number aperture included somewhere? ?How do we know what bus numbers are available for allocation under each bridge?

Not yet. I don't think DT imposes a bus number allocation on PCI bridges. However the matching of DT nodes to PCI bridges is done based on the bus number. For that you provide a bus-ranges property which defines the bus aperture of the given PCI bridge. The DT matching code compares the first cell of this property with the primary bus number of the bridge.

Quoted 8 lines

I don't fully understand this, but I can tell you that things don't work very well if we don't know the aperture. We can make assumptions, like the root bus is 00, and then enumerate everything reachable from there. But then all we know is the largest bus number actually reachable from bus 00, which is usually smaller then the end of the aperture. We don't know how many unused bus numbers there are in the aperture, so we can't safely allocate any for hot-added devices.

I think DT support for PCI is lacking in a lot of areas. PowerPC seems to be the only architecture actively setting up busses according to the bus-range property specified in the DT. All other architectures seem to not pre-allocate bus apertures and go with the default instead. From what you say that means hot-plugging is out. Although I don't think the Tegra PCIe controller even supports hot-plugging.

Quoted 43 lines
Quoted 37 lines

This is in fact somewhat counter-productive because it requires you to hard-code the PCI hierarchy within the DT and you loose a lot of the probing functionality. This is not much of an issue for typical PCI endpoints (like network cards) but becomes a problem if you have a PCI endpoint that implements an I2C bus and you want to match I2C slaves on that bus to device nodes so that the kernel can parse and instantiate them properly. I guess in the latter cases hard-coding the PCI tree in DT is not actually a drawback, though.

Quoted 3 lines

I see mention of config space. ?Is some of that referring to the ECAM as in 7.2.2 of the PCIe spec v3.0 (what we refer to as MMCONFIG on x86)?

I only have access to the PCIe 2.0 specification, but it seems to contain the same 7.2.2 section. In fact it looks as though this particular controller indeed implements something similar to ECAM. The address mapping is a little different, though:

? ? ? ?A[(16 + n - 1):16]: bus number
? ? ? ?A[15:11]: device number
? ? ? ?A[10:8]: function number
? ? ? ?A[7:2]: register number
? ? ? ?A[1:0]: unused

That information comes directly from the driver and I have no access to the corresponding documentation. It seems like the extended configuration space is accessed using the same mapping but starting at a different base address.

But now that you mention it, maybe the driver code is buggy here, and the controller indeed implements ECAM. Furthermore it also seems like the current code doesn't work for the extended configuration space because while the correct offset into the extended configuration space is chosen, the access to registers is done using the same mapping as above, so instead of the 12 (10) bits required for the register number only 8 (6) are in fact used.

Quoted 5 lines

I wonder whether anyone's actually tested this.

Stephen: can you try to find out whether the Tegra PCIe controller indeed implements ECAM, or if this scheme is actually just a proprietary variant?

Quoted 5 lines

It'd be a real shame if they made up a proprietary scheme when ECAM seems to be required by the spec. I'm interested because the current MMCONFIG code seems unnecessarily x86-specific, and I expect every arch with PCIe would want to use ECAM, so maybe there's some chance for a generic implementation.

Since this is pretty well specified by PCIe, a generic implementation should be possible. We'll have to wait for some better documentation on Tegra to know whether this is actually ECAM or not.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120622/92ed485b/attachment-0001.sig>

#58 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 13 lines · Thierry Reding
Quoted 12 lines · Bjorn Helgaas
Quoted 9 lines · Thierry Reding
Quoted 2 lines

Is the bus number aperture included somewhere? How do we know what bus numbers are available for allocation under each bridge?

Not yet. I don't think DT imposes a bus number allocation on PCI bridges. However the matching of DT nodes to PCI bridges is done based on the bus number. For that you provide a bus-ranges property which defines the bus aperture of the given PCI bridge. The DT matching code compares the first cell of this property with the primary bus number of the bridge.

Quoted 8 lines
Quoted 8 lines

I don't fully understand this, but I can tell you that things don't work very well if we don't know the aperture. We can make assumptions, like the root bus is 00, and then enumerate everything reachable from there. But then all we know is the largest bus number actually reachable from bus 00, which is usually smaller then the end of the aperture. We don't know how many unused bus numbers there are in the aperture, so we can't safely allocate any for hot-added devices.

I believe the assumption today is that all bus numbers are ok on each root port, which is usually the case. There was something about a Power Mac that faked a single PCI bus number space across both an AGP and a PCIe domain in pmac_pci_fixup_u4_of_node(), but I think that is the exception.

Is there any requirement to use a bus aperture on non-PC hardware?

Quoted 6 lines

I think DT support for PCI is lacking in a lot of areas. PowerPC seems to be the only architecture actively setting up busses according to the bus-range property specified in the DT. All other architectures seem to not pre-allocate bus apertures and go with the default instead. From what you say that means hot-plugging is out. Although I don't think the Tegra PCIe controller even supports hot-plugging.

If the default is allowing any bus numbers, and that matches the hardware capabilities, I think hot-plugging would work.

Arnd

maintainer
#59 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 23 lines · Arnd Bergmann
Quoted 13 lines · Thierry Reding
Quoted 12 lines · Bjorn Helgaas
Quoted 9 lines · Thierry Reding
Quoted 2 lines

Is the bus number aperture included somewhere? ?How do we know what bus numbers are available for allocation under each bridge?

Not yet. I don't think DT imposes a bus number allocation on PCI bridges. However the matching of DT nodes to PCI bridges is done based on the bus number. For that you provide a bus-ranges property which defines the bus aperture of the given PCI bridge. The DT matching code compares the first cell of this property with the primary bus number of the bridge.

Quoted 8 lines
Quoted 8 lines

I don't fully understand this, but I can tell you that things don't work very well if we don't know the aperture. ?We can make assumptions, like the root bus is 00, and then enumerate everything reachable from there. ?But then all we know is the largest bus number actually reachable from bus 00, which is usually smaller then the end of the aperture. ?We don't know how many unused bus numbers there are in the aperture, so we can't safely allocate any for hot-added devices.

Quoted 7 lines

I believe the assumption today is that all bus numbers are ok on each root port, which is usually the case. There was something about a Power Mac that faked a single PCI bus number space across both an AGP and a PCIe domain in pmac_pci_fixup_u4_of_node(), but I think that is the exception.

Is there any requirement to use a bus aperture on non-PC hardware?

The requirement (if there is one) isn't anything related to PC-ness. I just don't understand how things can actually work if two host bridges both claim the same bus number. If we do a config read to that bus, both bridges should claim it and turn it into config cycles on their respective root buses, and we should get two responses. I would expect the second response to cause an "unexpected response" machine check or similar.

Beyond that, Yinghai's recent "busn-alloc" work (now in my -next branch) tracks bus number assignments using a struct resource tree, and that obviously won't work with overlaps. Here's one of the relevant commits:
http://git.kernel.org/?p=linux/kernel/git/helgaas/pci.git;a=commitdiff;h=5cc62c202211096ec26309722ec27455d52c8726

Quoted 11 lines
Quoted 6 lines

I think DT support for PCI is lacking in a lot of areas. PowerPC seems to be the only architecture actively setting up busses according to the bus-range property specified in the DT. All other architectures seem to not pre-allocate bus apertures and go with the default instead. From what you say that means hot-plugging is out. Although I don't think the Tegra PCIe controller even supports hot-plugging.

If the default is allowing any bus numbers, and that matches the hardware capabilities, I think hot-plugging would work.

? ? ? ?Arnd

#60 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 7 lines · Bjorn Helgaas

The requirement (if there is one) isn't anything related to PC-ness. I just don't understand how things can actually work if two host bridges both claim the same bus number. If we do a config read to that bus, both bridges should claim it and turn it into config cycles on their respective root buses, and we should get two responses. I would expect the second response to cause an "unexpected response" machine check or similar.

But each PCI domain has its own config space, so if you do a config read for one bus, it's always relative to the domain.

The part that is specific to PCs is that they don't have PCI domains normally.

Arnd

maintainer
#61 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 11 lines · Arnd Bergmann
Quoted 7 lines · Bjorn Helgaas

The requirement (if there is one) isn't anything related to PC-ness. I just don't understand how things can actually work if two host bridges both claim the same bus number. ?If we do a config read to that bus, both bridges should claim it and turn it into config cycles on their respective root buses, and we should get two responses. ?I would expect the second response to cause an "unexpected response" machine check or similar.

But each PCI domain has its own config space, so if you do a config read for one bus, it's always relative to the domain.

Oh, I see! I totally missed the fact that each host bridge was in its own domain. If each has its own domain, then the bus number aperture can certainly be [bus 00-ff] and there's no problem.

#62 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 11 lines · Bjorn Helgaas
Quoted 9 lines · Arnd Bergmann
Quoted 7 lines · Bjorn Helgaas

The requirement (if there is one) isn't anything related to PC-ness. I just don't understand how things can actually work if two host bridges both claim the same bus number. If we do a config read to that bus, both bridges should claim it and turn it into config cycles on their respective root buses, and we should get two responses. I would expect the second response to cause an "unexpected response" machine check or similar.

Quoted 6 lines
Quoted 2 lines

But each PCI domain has its own config space, so if you do a config read for one bus, it's always relative to the domain.

Oh, I see! I totally missed the fact that each host bridge was in its own domain. If each has its own domain, then the bus number aperture can certainly be [bus 00-ff] and there's no problem.

Right. On my side, it took me a while to figure out that you can actually have multiple root ports in one domain ;-)

Arnd

#63 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

In reply to Arnd Bergmann
Quoted 2 lines · Arnd Bergmann

The part that is specific to PCs is that they don't have PCI domains normally.

Scratch that, PCs have moved on beyond that long ago, I just wasn't aware that they also do that now. That was only true before mmconfig.

Arnd

#64 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

In reply to Thierry Reding

On 06/22/2012 05:00 AM, Thierry Reding wrote:
...

Quoted 3 lines

Stephen: can you try to find out whether the Tegra PCIe controller indeed implements ECAM, or if this scheme is actually just a proprietary variant?

Sure. I have added this request to the bug I filed requesting more complete PCIe host documentation.

#65 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 8 lines · Stephen Warren

On 06/22/2012 05:00 AM, Thierry Reding wrote:
...

Quoted 3 lines

Stephen: can you try to find out whether the Tegra PCIe controller indeed implements ECAM, or if this scheme is actually just a proprietary variant?

Sure. I have added this request to the bug I filed requesting more complete PCIe host documentation.

I've received unofficial confirmation that we do indeed implement a non-standard/non-ECAM mapping, and what's in our driver matches our HW.

maintainer
#66 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 7 lines · Stephen Warren
Quoted 6 lines · Stephen Warren

On 06/22/2012 05:00 AM, Thierry Reding wrote:
...

Quoted 3 lines

Stephen: can you try to find out whether the Tegra PCIe controller indeed implements ECAM, or if this scheme is actually just a proprietary variant?

Quoted 5 lines
Quoted 2 lines

Sure. I have added this request to the bug I filed requesting more complete PCIe host documentation.

I've received unofficial confirmation that we do indeed implement a non-standard/non-ECAM mapping, and what's in our driver matches our HW.

Interesting. A generic ECAM/MMCONFIG solution might still be worth thinking about. We could easily have a hook to encapsulate the address mapping function, while still sharing the resource management (request_region(), etc). Not any kind of requirement for the current patch series, of course, just possible future work.

Bjorn

#67 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

In reply to Stephen Warren
Quoted 7 lines · Stephen Warren
Quoted 6 lines · Stephen Warren

On 06/22/2012 05:00 AM, Thierry Reding wrote:
...

Quoted 3 lines

Stephen: can you try to find out whether the Tegra PCIe controller indeed implements ECAM, or if this scheme is actually just a proprietary variant?

Quoted 5 lines
Quoted 2 lines

Sure. I have added this request to the bug I filed requesting more complete PCIe host documentation.

I've received unofficial confirmation that we do indeed implement a non-standard/non-ECAM mapping, and what's in our driver matches our HW.

What I don't quite see yet is how the extended configuration space is supposed to work with the current driver. The PCIE_CONF_* macros don't provide for registers >= 256. Passing a value higher than that will mess with the device function field.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120625/62af3efd/attachment.sig>

#68 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 10 lines · Thierry Reding
Quoted 9 lines · Stephen Warren
Quoted 7 lines · Stephen Warren

On 06/22/2012 05:00 AM, Thierry Reding wrote: ...

Quoted 3 lines

Stephen: can you try to find out whether the Tegra PCIe controller indeed implements ECAM, or if this scheme is actually just a proprietary variant?

Sure. I have added this request to the bug I filed requesting more complete PCIe host documentation.

Quoted 8 lines
Quoted 3 lines

I've received unofficial confirmation that we do indeed implement a non-standard/non-ECAM mapping, and what's in our driver matches our HW.

What I don't quite see yet is how the extended configuration space is supposed to work with the current driver. The PCIE_CONF_* macros don't provide for registers >= 256. Passing a value higher than that will mess with the device function field.

The current downstream driver is incorrect for that case. We should be updating it (at least, I filed a bug to do this).

Here's how the HW works (I believe this information should be in some future version of the TRM):

There are 3 address spaces:

* The CPU bus.

* An internal (to the PCIe controller) 40-bit address space. Apparently the layout is HyperTransport-based. Whether HT defines this, or whether our HW engineers are referring to our particular implementation of HT, I'm not sure.

* The PCIe external bus.

Accesses from the CPU to the PCIe controller's 1GB aperture are mapped into the 40-bit bus using the BAR configurations in the PCIe controller; I believe this is what tegra_pcie_setup_translations() is configuring in our downstream driver.

Accesses are then mapped from this 40-bit bus to the external 32-bit bus, I believe using a hard-coded mapping, which I believe may be inherited from (our implementation of?) HyperTransport

For config and extended config accesses the mapping from the internal to external bus is as follows:

In the case of PCICFG space,
addr[39:28]=12'hFDF,
addr[27:24]=4'hE means type 0 and addr[27:24]=4'hF means type 1, addr[23:16]=bus number
addr[15:11]=device number
addr[10:8]=function number
addr[7:0]=register number

In the case of EXTCFG space,
addr[39:32]=8'hFE,
addr[31:28]=4'h0 means type 0 and addr[31:28]=4'h1 means type 1, addr[27:24]=upper register number (i.e. register number[11:8]) addr[23:16]=bus number
addr[15:11]=device number
addr[10:8]=function number
addr[7:0]=register number (i.e. register number[7:0])

(in actual fact, the HW matches the top 16 or 12 bits to determine config/ext-config and transaction type, so the top two fields in the lists above should really be considered merged)

I hope this helps!

#69 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 20 lines · Stephen Warren
Quoted 10 lines · Thierry Reding
Quoted 9 lines · Stephen Warren
Quoted 7 lines · Stephen Warren

On 06/22/2012 05:00 AM, Thierry Reding wrote: ...

Quoted 3 lines

Stephen: can you try to find out whether the Tegra PCIe controller indeed implements ECAM, or if this scheme is actually just a proprietary variant?

Sure. I have added this request to the bug I filed requesting more complete PCIe host documentation.

Quoted 8 lines
Quoted 3 lines

I've received unofficial confirmation that we do indeed implement a non-standard/non-ECAM mapping, and what's in our driver matches our HW.

What I don't quite see yet is how the extended configuration space is supposed to work with the current driver. The PCIE_CONF_* macros don't provide for registers >= 256. Passing a value higher than that will mess with the device function field.

Quoted 5 lines

The current downstream driver is incorrect for that case. We should be updating it (at least, I filed a bug to do this).

Here's how the HW works (I believe this information should be in some future version of the TRM):

Definitely. I'm having a hard time grasping all of this by just looking at the code. Some sort of functional description (like what you provide here) would be really useful.

Quoted 11 lines

There are 3 address spaces:

* The CPU bus.

* An internal (to the PCIe controller) 40-bit address space. Apparently the layout is HyperTransport-based. Whether HT defines this, or whether our HW engineers are referring to our particular implementation of HT, I'm not sure.

* The PCIe external bus.

Quoted 8 lines

Accesses from the CPU to the PCIe controller's 1GB aperture are mapped into the 40-bit bus using the BAR configurations in the PCIe controller; I believe this is what tegra_pcie_setup_translations() is configuring in our downstream driver.

Accesses are then mapped from this 40-bit bus to the external 32-bit bus, I believe using a hard-coded mapping, which I believe may be inherited from (our implementation of?) HyperTransport

This seems to be what is referred to as the FPCI in the TRM and the driver.

Quoted 20 lines

For config and extended config accesses the mapping from the internal to external bus is as follows:

In the case of PCICFG space,
addr[39:28]=12'hFDF,
addr[27:24]=4'hE means type 0 and addr[27:24]=4'hF means type 1, addr[23:16]=bus number
addr[15:11]=device number
addr[10:8]=function number
addr[7:0]=register number

In the case of EXTCFG space,
addr[39:32]=8'hFE,
addr[31:28]=4'h0 means type 0 and addr[31:28]=4'h1 means type 1, addr[27:24]=upper register number (i.e. register number[11:8]) addr[23:16]=bus number
addr[15:11]=device number
addr[10:8]=function number
addr[7:0]=register number (i.e. register number[7:0])

Quoted 3 lines

(in actual fact, the HW matches the top 16 or 12 bits to determine config/ext-config and transaction type, so the top two fields in the lists above should really be considered merged)

Yes, this actually matches with the driver. Config space accesses are mapped to 0xfdff0000 and ext. config space accesses go to 0xfe100000.

Quoted 1 line

I hope this helps!

I don't know how this works out for what Bjorn had in mind, but at least it'll allow the driver to be fixed for extended config space accesses.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120627/1018957d/attachment.sig>

#70 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

In reply to Thierry Reding

On 06/21/2012 12:47 AM, Thierry Reding wrote:
...

Quoted 10 lines

Everybody seems to be happy with this approach, so I'll give it a shot. There is one thing I'm still unsure about, though. What if somebody uses the above scheme and maps the registers to the wrong port. The same goes for the nvidia,ctrl-offset property. It needs to match the register offset because they are directly related. I suppose we could leave that property away and look up the register via the port index (which, as Stephen already said, we'll have to do in other places anyway, unless we list all bit positions in the DT).

Quoted 3 lines

Can we safely ignore such issues and assume the device tree to always be right? Should we just not care if somebody uses it wrongly?

I think that's pretty much the same thing as plain putting the wrong reg property into any node - the value is wrong, so it doesn't work. There's not too much you can do about it.

I'd be happy to remove the nvidia,ctrl-offset property to avoid the need to specify basically the same information multiple times though; nothing wrong with making it easier to write the correct DT content.

#71 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

In reply to Thierry Reding
Quoted 138 lines · Thierry Reding
Quoted 133 lines · Mitch Bradley
Quoted 114 lines · Thierry Reding
Quoted 41 lines · Thierry Reding
Quoted 35 lines · Stephen Warren
Quoted 2 lines · Thierry Reding
Quoted 1 line · Stephen Warren

On 06/14/2012 03:19 AM, Thierry Reding wrote:

...

Quoted 24 lines
Quoted 18 lines
Quoted 3 lines

#address-cells = <1>; #size-cells = <1>;

pci at 80000000 {

I'm still not convinced that using the address of the port's registers is the correct way to represent each port. The port index seems much more useful.

The main reason here is that there are a lot of registers that contain fields for each port - far more than the combination of this node's reg and ctrl-offset (which I assume is an address offset for just one example of this issue) properties can describe. The bit position and bit stride of these fields isn't necessarily the same in each register. Do we want a property like ctrl-offset for every single type of field in every single shared register that describes the location of the relevant data, or just a single "port ID" bit that can be applied to anything?

Quoted 5 lines

(Perhaps this isn't so obvious looking at the TRM since it doesn't document all registers, and I'm also looking at the Tegra30 documentation too, which might be more exposed to this - I haven't correlated all the documentation sources to be sure though)

Quoted 6 lines

I agree that maybe adding properties for each bit position or register offset may not work out too well. But I think it still makes sense to use the base address of the port's registers (see below). We could of course add some code to determine the index from the base address at initialization time and reuse the index where appropriate.

Quoted 4 lines

To me, working back from address to ID then using the ID to calculate some other addresses seems far more icky than just calculating all the addresses based off of one ID. But, I suppose this doesn't make a huge practical difference.

Quoted 6 lines

This really depends on the device vs. no device decision below. If we can make it work without needing an extra device for it, then using the index is certainly better. However, if we instantiate devices from the DT, then we have the address anyway and adding the index as a property would be redundant and error prone (what happens if somebody sets the index of the port at address 0x80000000 to 2?).

An additional problem with this is that we'd have to add the following to the pcie-controller node:

	#address-cells = <1>;
	#size-cells = <0>;

This will conflict with the "ranges" property, because suddenly we can no longer map the regions properly. Maybe Mitch can comment on whether this is possible or not?

To make it clearer what I'm talking about, here's the DT snippet again (with the compatible property removed from the pci@ nodes because they are no longer probed by a driver, the "simple-bus" removed from the pcie-controller node's compatible property removed and its #address- and #size-cells properties adjusted as described above).

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000>; /* extended configuration space */
		interrupts = <0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells = <1>;
		#size-cells = <0>;

		pci at 0 {
			reg = <2>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x81000000 0 0 0x80400000 0 0x00008000   /* I/O */
				  0x82000000 0 0 0x90000000 0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0 0xa0000000 0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x110>;
			nvidia,num-lanes = <2>;
		};

		pci at 1 {
			reg = <1>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x81000000 0 0 0x80408000 0 0x00008000   /* I/O */
				  0x82000000 0 0 0x98000000 0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0 0xa8000000 0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x118>;
			nvidia,num-lanes = <2>;
		};
	};
Quoted 4 lines

AIUI none of the ranges properties are valid anymore, because the bus represented by pcie-controller no longer reflects the truth, namely that it translates the CPU address space to the PCI address space.

I think you can use a small-integer port number as an address by defining the intermediate address space properly, and using appropriate ranges above and below. Here's a swag at how that would look.

I present three versions, using different choices for the intermediate address space encoding. The intermediate address space may seem somewhat artificial, in that it decouples the "linear pass through of ranges" between the lower PCI address space and the upper CPU address space. But in another sense, it accurately reflects that fact that the bus bridge "slices and dices" that linear address space into non-contiguous pieces.

Quoted 3 lines

Note that I'm also fixing a problem that I neglected to mention earlier - namely the fact that config space is part of the child PCI address space so it must be passed through.

Quoted 7 lines

This doesn't quite match how the Tegra PCIe controller works. Basically, every access to a device's (extended) configuration space goes through a single region of memory-mapped registers, independent of which port is the parent of the device.

Is it okay to pass both configuration spaces via the ranges property but still list them in the reg property of the controller?

It's a small hierarchy violation, but I expect that it would work in practice.

Quoted 83 lines
Quoted 65 lines
Version A - 3 address cells:  In this version, the intermediate
address space has 3 cells:  port#, address type, offset.  Address

type is
0 : root port
1 : config space
2 : extended config space
3 : I/O
4 : non-prefetchable memory
5 : prefetchable memory.

The third cell "offset" is necessary so that the size field has a number space that can include it.

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200>; /* extended configuration space */
		interrupts = <0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0 0 0  0x80000000 0x00001000   /* Root port 0 */
			  0 1 0  0x80004000 0x00080000   /* Port 0 config space */
			  0 2 0  0x80104000 0x00080000   /* Port 0 ext config space *
			  0 3 0  0x80400000 0x00008000   /* Port 0 downstream I/O */
			  0 4 0  0x90000000 0x08000000   /* Port 0 non-prefetchable memory */
			  0 5 0  0xa0000000 0x08000000   /* Port 0 prefetchable memory */

			  1 0 0  0x80001000 0x00001000   /* Root port 1 */
			  1 1 0  0x80004000 0x00080000   /* Port 1 config space */
			  1 2 0  0x80184000 0x00080000   /* Port 1 ext config space */
			  1 3 0  0x80408000 0x00010000   /* Port 1 downstream I/O */
			  1 4 0  0x98000000 0x08000000   /* Port 1 non-prefetchable memory */
			  1 5 0  0xa0000000 0x08000000>; /* Port 1 prefetchable memory */

		#address-cells = <3>;
		#size-cells = <1>;

		pci at 0 {
			reg = <0 0 0 0x1000>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x80000000 0 0  0 1 0  0 0x00080000   /* config */
				  0x90000000 0 0  0 2 0  0 0x00080000   /* extended config */
				  0x81000000 0 0  0 3 0  0 0x00008000   /* I/O */
				  0x82000000 0 0  0 4 0  0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0  0 5 0  0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x110>;
			nvidia,num-lanes = <2>;
		};


		pci at 1 {
			reg = <1 0 0 0x1000>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x80000000 0 0  1 1 0  0 0x00080000   /* config */
Quoted 8 lines
				  0x90000000 0 0  1 2 0  0 0x00080000   /* extended config */
				  0x81000000 0 0  1 3 0  0 0x00008000   /* I/O */
				  0x82000000 0 0  1 4 0  0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0  1 5 0  0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x118>;
			nvidia,num-lanes = <2>;
		};

Everybody seems to be happy with this approach, so I'll give it a shot. There is one thing I'm still unsure about, though. What if somebody uses the above scheme and maps the registers to the wrong port. The same goes for the nvidia,ctrl-offset property. It needs to match the register offset because they are directly related. I suppose we could leave that property away and look up the register via the port index (which, as Stephen already said, we'll have to do in other places anyway, unless we list all bit positions in the DT).

Quoted 2 lines

Can we safely ignore such issues and assume the device tree to always be right? Should we just not care if somebody uses it wrongly?

To the extent that the device tree is the definitive answer about the system addressing, if you get it wrong, either the system will not work or the OS isn't paying attention to that part of the device tree, hardcoding the right answer.

Quoted 3 lines

Thierry

#72 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

In reply to Mitch Bradley
Quoted 177 lines · Mitch Bradley
Quoted 114 lines · Thierry Reding
Quoted 41 lines · Thierry Reding
Quoted 35 lines · Stephen Warren
Quoted 2 lines · Thierry Reding
Quoted 1 line · Stephen Warren

On 06/14/2012 03:19 AM, Thierry Reding wrote:

...

Quoted 24 lines
Quoted 18 lines
Quoted 3 lines

#address-cells = <1>; #size-cells = <1>;

pci at 80000000 {

I'm still not convinced that using the address of the port's registers is the correct way to represent each port. The port index seems much more useful.

The main reason here is that there are a lot of registers that contain fields for each port - far more than the combination of this node's reg and ctrl-offset (which I assume is an address offset for just one example of this issue) properties can describe. The bit position and bit stride of these fields isn't necessarily the same in each register. Do we want a property like ctrl-offset for every single type of field in every single shared register that describes the location of the relevant data, or just a single "port ID" bit that can be applied to anything?

Quoted 5 lines

(Perhaps this isn't so obvious looking at the TRM since it doesn't document all registers, and I'm also looking at the Tegra30 documentation too, which might be more exposed to this - I haven't correlated all the documentation sources to be sure though)

Quoted 6 lines

I agree that maybe adding properties for each bit position or register offset may not work out too well. But I think it still makes sense to use the base address of the port's registers (see below). We could of course add some code to determine the index from the base address at initialization time and reuse the index where appropriate.

Quoted 4 lines

To me, working back from address to ID then using the ID to calculate some other addresses seems far more icky than just calculating all the addresses based off of one ID. But, I suppose this doesn't make a huge practical difference.

Quoted 6 lines

This really depends on the device vs. no device decision below. If we can make it work without needing an extra device for it, then using the index is certainly better. However, if we instantiate devices from the DT, then we have the address anyway and adding the index as a property would be redundant and error prone (what happens if somebody sets the index of the port at address 0x80000000 to 2?).

An additional problem with this is that we'd have to add the following to the pcie-controller node:

	#address-cells = <1>;
	#size-cells = <0>;

This will conflict with the "ranges" property, because suddenly we can no longer map the regions properly. Maybe Mitch can comment on whether this is possible or not?

To make it clearer what I'm talking about, here's the DT snippet again (with the compatible property removed from the pci@ nodes because they are no longer probed by a driver, the "simple-bus" removed from the pcie-controller node's compatible property removed and its #address- and #size-cells properties adjusted as described above).

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000>; /* extended configuration space */
		interrupts = <0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells = <1>;
		#size-cells = <0>;

		pci at 0 {
			reg = <2>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x81000000 0 0 0x80400000 0 0x00008000   /* I/O */
				  0x82000000 0 0 0x90000000 0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0 0xa0000000 0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x110>;
			nvidia,num-lanes = <2>;
		};

		pci at 1 {
			reg = <1>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x81000000 0 0 0x80408000 0 0x00008000   /* I/O */
				  0x82000000 0 0 0x98000000 0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0 0xa8000000 0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x118>;
			nvidia,num-lanes = <2>;
		};
	};
Quoted 4 lines

AIUI none of the ranges properties are valid anymore, because the bus represented by pcie-controller no longer reflects the truth, namely that it translates the CPU address space to the PCI address space.

I think you can use a small-integer port number as an address by defining the intermediate address space properly, and using appropriate ranges above and below. Here's a swag at how that would look.

I present three versions, using different choices for the intermediate address space encoding. The intermediate address space may seem somewhat artificial, in that it decouples the "linear pass through of ranges" between the lower PCI address space and the upper CPU address space. But in another sense, it accurately reflects that fact that the bus bridge "slices and dices" that linear address space into non-contiguous pieces.

Note that I'm also fixing a problem that I neglected to mention earlier - namely the fact that config space is part of the child PCI address space so it must be passed through.

Version A - 3 address cells:  In this version, the intermediate
address space has 3 cells:  port#, address type, offset.  Address

type is
0 : root port
1 : config space
2 : extended config space
3 : I/O
4 : non-prefetchable memory
5 : prefetchable memory.

The third cell "offset" is necessary so that the size field has a number space that can include it.

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200>; /* extended configuration space */
		interrupts = <0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0 0 0  0x80000000 0x00001000   /* Root port 0 */
			  0 1 0  0x80004000 0x00080000   /* Port 0 config space */
			  0 2 0  0x80104000 0x00080000   /* Port 0 ext config space *
			  0 3 0  0x80400000 0x00008000   /* Port 0 downstream I/O */
			  0 4 0  0x90000000 0x08000000   /* Port 0 non-prefetchable memory */
			  0 5 0  0xa0000000 0x08000000   /* Port 0 prefetchable memory */

			  1 0 0  0x80001000 0x00001000   /* Root port 1 */
			  1 1 0  0x80004000 0x00080000   /* Port 1 config space */
			  1 2 0  0x80184000 0x00080000   /* Port 1 ext config space */
			  1 3 0  0x80408000 0x00010000   /* Port 1 downstream I/O */
			  1 4 0  0x98000000 0x08000000   /* Port 1 non-prefetchable memory */
			  1 5 0  0xa0000000 0x08000000>; /* Port 1 prefetchable memory */

		#address-cells = <3>;
		#size-cells = <1>;

		pci at 0 {
			reg = <0 0 0 0x1000>;

[...]

Quoted 4 lines
		};

		pci at 1 {
			reg = <1 0 0 0x1000>;

[...]

Quoted 1 line
		};

It seems like this isn't working properly. For some reason both the reg property of pci at 0 and pci at 1 are translated to the same parent address 0x80000000. I'll have to investigate where exactly this goes wrong.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120622/a9e3ca1d/attachment-0001.sig>

#73 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 181 lines · Thierry Reding
Quoted 177 lines · Mitch Bradley
Quoted 114 lines · Thierry Reding
Quoted 41 lines · Thierry Reding
Quoted 35 lines · Stephen Warren
Quoted 2 lines · Thierry Reding
Quoted 1 line · Stephen Warren

On 06/14/2012 03:19 AM, Thierry Reding wrote:

...

Quoted 24 lines
Quoted 18 lines
Quoted 3 lines

#address-cells = <1>; #size-cells = <1>;

pci at 80000000 {

I'm still not convinced that using the address of the port's registers is the correct way to represent each port. The port index seems much more useful.

The main reason here is that there are a lot of registers that contain fields for each port - far more than the combination of this node's reg and ctrl-offset (which I assume is an address offset for just one example of this issue) properties can describe. The bit position and bit stride of these fields isn't necessarily the same in each register. Do we want a property like ctrl-offset for every single type of field in every single shared register that describes the location of the relevant data, or just a single "port ID" bit that can be applied to anything?

Quoted 5 lines

(Perhaps this isn't so obvious looking at the TRM since it doesn't document all registers, and I'm also looking at the Tegra30 documentation too, which might be more exposed to this - I haven't correlated all the documentation sources to be sure though)

Quoted 6 lines

I agree that maybe adding properties for each bit position or register offset may not work out too well. But I think it still makes sense to use the base address of the port's registers (see below). We could of course add some code to determine the index from the base address at initialization time and reuse the index where appropriate.

Quoted 4 lines

To me, working back from address to ID then using the ID to calculate some other addresses seems far more icky than just calculating all the addresses based off of one ID. But, I suppose this doesn't make a huge practical difference.

Quoted 6 lines

This really depends on the device vs. no device decision below. If we can make it work without needing an extra device for it, then using the index is certainly better. However, if we instantiate devices from the DT, then we have the address anyway and adding the index as a property would be redundant and error prone (what happens if somebody sets the index of the port at address 0x80000000 to 2?).

An additional problem with this is that we'd have to add the following to the pcie-controller node:

	#address-cells = <1>;
	#size-cells = <0>;

This will conflict with the "ranges" property, because suddenly we can no longer map the regions properly. Maybe Mitch can comment on whether this is possible or not?

To make it clearer what I'm talking about, here's the DT snippet again (with the compatible property removed from the pci@ nodes because they are no longer probed by a driver, the "simple-bus" removed from the pcie-controller node's compatible property removed and its #address- and #size-cells properties adjusted as described above).

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000>; /* extended configuration space */
		interrupts = <0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells = <1>;
		#size-cells = <0>;

		pci at 0 {
			reg = <2>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x81000000 0 0 0x80400000 0 0x00008000   /* I/O */
				  0x82000000 0 0 0x90000000 0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0 0xa0000000 0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x110>;
			nvidia,num-lanes = <2>;
		};

		pci at 1 {
			reg = <1>;
			status = "disabled";

			#address-cells = <3>;
			#size-cells = <2>;

			ranges = <0x81000000 0 0 0x80408000 0 0x00008000   /* I/O */
				  0x82000000 0 0 0x98000000 0 0x08000000   /* non-prefetchable memory */
				  0xc2000000 0 0 0xa8000000 0 0x08000000>; /* prefetchable memory */

			nvidia,ctrl-offset = <0x118>;
			nvidia,num-lanes = <2>;
		};
	};
Quoted 4 lines

AIUI none of the ranges properties are valid anymore, because the bus represented by pcie-controller no longer reflects the truth, namely that it translates the CPU address space to the PCI address space.

I think you can use a small-integer port number as an address by defining the intermediate address space properly, and using appropriate ranges above and below. Here's a swag at how that would look.

I present three versions, using different choices for the intermediate address space encoding. The intermediate address space may seem somewhat artificial, in that it decouples the "linear pass through of ranges" between the lower PCI address space and the upper CPU address space. But in another sense, it accurately reflects that fact that the bus bridge "slices and dices" that linear address space into non-contiguous pieces.

Note that I'm also fixing a problem that I neglected to mention earlier - namely the fact that config space is part of the child PCI address space so it must be passed through.

Version A - 3 address cells:  In this version, the intermediate
address space has 3 cells:  port#, address type, offset.  Address

type is
0 : root port
1 : config space
2 : extended config space
3 : I/O
4 : non-prefetchable memory
5 : prefetchable memory.

The third cell "offset" is necessary so that the size field has a number space that can include it.

	pcie-controller {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200>; /* extended configuration space */
		interrupts = <0 98 0x04   /* controller interrupt */
			      0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0 0 0  0x80000000 0x00001000   /* Root port 0 */
			  0 1 0  0x80004000 0x00080000   /* Port 0 config space */
			  0 2 0  0x80104000 0x00080000   /* Port 0 ext config space *
			  0 3 0  0x80400000 0x00008000   /* Port 0 downstream I/O */
			  0 4 0  0x90000000 0x08000000   /* Port 0 non-prefetchable memory */
			  0 5 0  0xa0000000 0x08000000   /* Port 0 prefetchable memory */

			  1 0 0  0x80001000 0x00001000   /* Root port 1 */
			  1 1 0  0x80004000 0x00080000   /* Port 1 config space */
			  1 2 0  0x80184000 0x00080000   /* Port 1 ext config space */
			  1 3 0  0x80408000 0x00010000   /* Port 1 downstream I/O */
			  1 4 0  0x98000000 0x08000000   /* Port 1 non-prefetchable memory */
			  1 5 0  0xa0000000 0x08000000>; /* Port 1 prefetchable memory */

		#address-cells = <3>;
		#size-cells = <1>;

		pci at 0 {
			reg = <0 0 0 0x1000>;

[...]

Quoted 2 lines
		};
Quoted 8 lines
Quoted 2 lines
		pci at 1 {
			reg = <1 0 0 0x1000>;

[...]

Quoted 1 line
		};

It seems like this isn't working properly. For some reason both the reg property of pci at 0 and pci at 1 are translated to the same parent address 0x80000000. I'll have to investigate where exactly this goes wrong.

So it turns out that while of_read_number() can actually read any number of cells, only the two least significant are kept because it returns a u64. Since of_bus_default_map() uses of_read_number() the addresses <0 0 0> and <1 0 0> are in fact the same. I'm not sure how best to solve this. I'm not aware of a 128 bit integer type in the kernel, so I guess the better alternative would be to fix of_bus_default_map() to cope with #address-cells > 2 properly.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120622/ce370014/attachment.sig>

#74 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 11 lines · Thierry Reding
Quoted 3 lines

It seems like this isn't working properly. For some reason both the reg property of pci at 0 and pci at 1 are translated to the same parent address 0x80000000. I'll have to investigate where exactly this goes wrong.

So it turns out that while of_read_number() can actually read any number of cells, only the two least significant are kept because it returns a u64. Since of_bus_default_map() uses of_read_number() the addresses <0 0 0> and <1 0 0> are in fact the same. I'm not sure how best to solve this. I'm not aware of a 128 bit integer type in the kernel, so I guess the better alternative would be to fix of_bus_default_map() to cope with #address-cells > 2 properly.

of_translate_address should get it right. Which codes uses of_read_number()? Can it be converted to use of_translate_address()?

Arnd

#75 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 13 lines · Arnd Bergmann
Quoted 11 lines · Thierry Reding
Quoted 3 lines

It seems like this isn't working properly. For some reason both the reg property of pci at 0 and pci at 1 are translated to the same parent address 0x80000000. I'll have to investigate where exactly this goes wrong.

So it turns out that while of_read_number() can actually read any number of cells, only the two least significant are kept because it returns a u64. Since of_bus_default_map() uses of_read_number() the addresses <0 0 0> and <1 0 0> are in fact the same. I'm not sure how best to solve this. I'm not aware of a 128 bit integer type in the kernel, so I guess the better alternative would be to fix of_bus_default_map() to cope with #address-cells > 2 properly.

Quoted 2 lines

of_translate_address should get it right. Which codes uses of_read_number()? Can it be converted to use of_translate_address()?

Actually this is from of_translate_address(). The calling sequence looks like this:

	of_address_to_resource()
	  __of_address_to_resource()
	    of_translate_address()
	      __of_translate_address()
	        of_translate_one()
	          of_bus_default_map()
	            of_read_number()

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120622/96546a0c/attachment.sig>

#76 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 10 lines · Thierry Reding

Actually this is from of_translate_address(). The calling sequence looks like this:

        of_address_to_resource()
          __of_address_to_resource()
            of_translate_address()
              __of_translate_address()
                of_translate_one()
                  of_bus_default_map()
                    of_read_number()

Ok, I see.

This looks like a problem in of_bus_default_map, which expects to see only 64 bit addresses at most. of_bus_pci_map by comparison handles the pci addresses with three cells.

If I read this correctly, this fix is to make sure we compare the upper cells of the address in of_bus_default_map:

static u64 of_bus_default_map(u32 *addr, const __be32 *range,
int na, int ns, int pna)

{
        u64 cp, s, da;

        cp = of_read_number(range, na);
        s  = of_read_number(range + na + pna, ns);
        da = of_read_number(addr, na);

        pr_debug("OF: default map, cp=%llx, s=%llx, da=%llx\n",
                 (unsigned long long)cp, (unsigned long long)s,
                 (unsigned long long)da);

        if (da < cp || da >= (cp + s))
                return OF_BAD_ADDR;
        return da - cp;
}

How about adding code like:

	if ((na > 2) && memcmp(range, addr, na * 4) != 0)
		return OF_BAD_ADDR;

This won't handle entries with #size-cells>2 or those that span a 64-bit boundary, but I think it will work for all relevant cases.

Arnd

#77 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

In reply to Thierry Reding
Quoted 7 lines · Thierry Reding
                pci at 80000000 {
                        reg = <0x80000000 0x00001000>;
                        status = "disabled";

                        #address-cells = <3>;
                        #size-cells = <2>;
Quoted 8 lines
                        ranges = <0x80400000 0x80400000 0x00008000   /* I/O */
                                  0x90000000 0x90000000 0x08000000   /* non-prefetchable memory */
                                  0xa0000000 0xa0000000 0x08000000>; /* prefetchable memory */

                        nvidia,ctrl-offset = <0x0>;
                        nvidia,num-lanes = <2>;
                };

I believe you will need an "interrupt-map" property here, to map the host interrupts to the INTA-INTD lines of the attached devices.

I'm not sure whether we want to have a device_type="pciex" property here. powerpc and sparc seem to use that information, to distinguish a pcie bus from pci or cardbus.

Arnd

#78 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 12 lines · Arnd Bergmann
Quoted 11 lines · Thierry Reding
                pci at 80000000 {
                        reg = <0x80000000 0x00001000>;
                        status = "disabled";

                        #address-cells = <3>;
                        #size-cells = <2>;

                        ranges = <0x80400000 0x80400000 0x00008000   /* I/O */
                                  0x90000000 0x90000000 0x08000000   /* non-prefetchable memory */
                                  0xa0000000 0xa0000000 0x08000000>; /* prefetchable memory */
Quoted 7 lines
Quoted 4 lines
                        nvidia,ctrl-offset = <0x0>;
                        nvidia,num-lanes = <2>;
                };

I believe you will need an "interrupt-map" property here, to map the host interrupts to the INTA-INTD lines of the attached devices.

Legacy interrupts are something I cannot test at all because I have no hardware that supports them.

Quoted 3 lines

I'm not sure whether we want to have a device_type="pciex" property here. powerpc and sparc seem to use that information, to distinguish a pcie bus from pci or cardbus.

That'd be rather useless information given that the Tegra is unlikely to support either PCI or CardBus at some point.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120614/b90536c5/attachment-0001.sig>

#79 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 6 lines · Thierry Reding
Quoted 3 lines

I believe you will need an "interrupt-map" property here, to map the host interrupts to the INTA-INTD lines of the attached devices.

Legacy interrupts are something I cannot test at all because I have no hardware that supports them.

Hmm, I thought all PCIe hardware has to support them when you do not enable MSI. What hardware do you have then?

Quoted 6 lines
Quoted 3 lines

I'm not sure whether we want to have a device_type="pciex" property here. powerpc and sparc seem to use that information, to distinguish a pcie bus from pci or cardbus.

That'd be rather useless information given that the Tegra is unlikely to support either PCI or CardBus at some point.

But the generic code does not know that.

Arnd

#80 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 10 lines · Arnd Bergmann
Quoted 6 lines · Thierry Reding
Quoted 3 lines

I believe you will need an "interrupt-map" property here, to map the host interrupts to the INTA-INTD lines of the attached devices.

Legacy interrupts are something I cannot test at all because I have no hardware that supports them.

Hmm, I thought all PCIe hardware has to support them when you do not enable MSI. What hardware do you have then?

The TEC (Tamonten Evaluation Carrier) has an FPGA which is connected to one of the Tegra PCIe ports and it only supports MSIs.

Quoted 8 lines
Quoted 6 lines
Quoted 3 lines

I'm not sure whether we want to have a device_type="pciex" property here. powerpc and sparc seem to use that information, to distinguish a pcie bus from pci or cardbus.

That'd be rather useless information given that the Tegra is unlikely to support either PCI or CardBus at some point.

But the generic code does not know that.

True. Still there's not much generic code on ARM, so maybe it'd be better to add it along with the corresponding code?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120614/ab4a7c31/attachment.sig>

#81 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 6 lines · Thierry Reding
Quoted 5 lines · Arnd Bergmann
Quoted 4 lines · Thierry Reding
Quoted 3 lines

I believe you will need an "interrupt-map" property here, to map the host interrupts to the INTA-INTD lines of the attached devices.

Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

Legacy interrupts are something I cannot test at all because I have no hardware that supports them.

Hmm, I thought all PCIe hardware has to support them when you do not enable MSI. What hardware do you have then?

The TEC (Tamonten Evaluation Carrier) has an FPGA which is connected to one of the Tegra PCIe ports and it only supports MSIs.

Ah, I see. FPGA based devices often have incomplete PCI support so that explains why you can't test it. The board also appears to have a PCIe mini port though, so anything that you could plug in there should also support LSI interrupts.

Quoted 11 lines
Quoted 8 lines
Quoted 6 lines
Quoted 3 lines

I'm not sure whether we want to have a device_type="pciex" property here. powerpc and sparc seem to use that information, to distinguish a pcie bus from pci or cardbus.

That'd be rather useless information given that the Tegra is unlikely to support either PCI or CardBus at some point.

But the generic code does not know that.

True. Still there's not much generic code on ARM, so maybe it'd be better to add it along with the corresponding code?

I hope we can make the PCI host probing architecture independent one day, instead of each architecture implementing their own. I'd say better put that property in there so we don't have to change it in case the future generic code will need it. It is part of the binding at
http://www.openfirmware.org/1275/bindings/pci/pci-express.txt after all.

Note that we should generally not make /code/ be written with the anticipation of a future extension, but anything that concerns interfaces to code outside of the kernel (firmware or user space) is best written in a conservative way to allow later changes.

Arnd

#82 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 13 lines · Arnd Bergmann
Quoted 12 lines · Thierry Reding
Quoted 10 lines · Arnd Bergmann
Quoted 6 lines · Thierry Reding
Quoted 3 lines

I believe you will need an "interrupt-map" property here, to map the host interrupts to the INTA-INTD lines of the attached devices.

Legacy interrupts are something I cannot test at all because I have no hardware that supports them.

Hmm, I thought all PCIe hardware has to support them when you do not enable MSI. What hardware do you have then?

Quoted 7 lines
Quoted 2 lines

The TEC (Tamonten Evaluation Carrier) has an FPGA which is connected to one of the Tegra PCIe ports and it only supports MSIs.

Ah, I see. FPGA based devices often have incomplete PCI support so that explains why you can't test it. The board also appears to have a PCIe mini port though, so anything that you could plug in there should also support LSI interrupts.

Yes, I haven't gotten my hands on a suitable module yet, but I'll try. I'm not very familiar with legacy interrupts, though, and I'll have to read up on the interrupt map bindings.

Quoted 9 lines
Quoted 9 lines
Quoted 8 lines
Quoted 6 lines
Quoted 3 lines

I'm not sure whether we want to have a device_type="pciex" property here. powerpc and sparc seem to use that information, to distinguish a pcie bus from pci or cardbus.

That'd be rather useless information given that the Tegra is unlikely to support either PCI or CardBus at some point.

But the generic code does not know that.

Quoted 8 lines
Quoted 2 lines

True. Still there's not much generic code on ARM, so maybe it'd be better to add it along with the corresponding code?

I hope we can make the PCI host probing architecture independent one day, instead of each architecture implementing their own. I'd say better put that property in there so we don't have to change it in case the future generic code will need it. It is part of the binding at
http://www.openfirmware.org/1275/bindings/pci/pci-express.txt after all.

There seems to be quite a lot in the PCI core already. Unfortunately every architecture seems to do things differently, so unification is probably going to be quite difficult.

Quoted 4 lines

Note that we should generally not make /code/ be written with the anticipation of a future extension, but anything that concerns interfaces to code outside of the kernel (firmware or user space) is best written in a conservative way to allow later changes.

Okay, I'll add the property.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120614/3c9c8a18/attachment.sig>

#83 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

In reply to Stephen Warren
Quoted 63 lines · Stephen Warren

On 06/12/2012 11:20 AM, Thierry Reding wrote:
...

Quoted 36 lines

I came up with the following alternative:

	pci {
		compatible = "nvidia,tegra20-pcie";
		reg = <0x80003000 0x00000800   /* PADS registers */
		       0x80003800 0x00000200   /* AFI registers */
		       0x80004000 0x00100000   /* configuration space */
		       0x80104000 0x00100000   /* extended configuration space */
		       0x80400000 0x00010000   /* downstream I/O */
		       0x90000000 0x10000000   /* non-prefetchable memory */
		       0xa0000000 0x10000000>; /* prefetchable memory */
		interrupts = <0 98 0x04   /* controller interrupt */
		              0 99 0x04>; /* MSI interrupt */
		status = "disabled";

		ranges = <0x80000000 0x80000000 0x00002000   /* 2 root ports */
			  0x80004000 0x80004000 0x00100000   /* configuration space */
			  0x80104000 0x80104000 0x00100000   /* extended configuration space */
			  0x80400000 0x80400000 0x00010000   /* downstream I/O */
			  0x90000000 0x90000000 0x10000000   /* non-prefetchable memory */
			  0xa0000000 0xa0000000 0x10000000>; /* prefetchable memory */

		#address-cells = <1>;
		#size-cells = <1>;

		port at 80000000 {
			reg = <0x80000000 0x00001000>;
			status = "disabled";
		};

		port at 80001000 {
			reg = <0x80001000 0x00001000>;
			status = "disabled";
		};
	};
Quoted 6 lines

The "ranges" property can probably be cleaned up a bit, but the most interesting part is the port@ children, which can simply be enabled in board DTS files by setting the status property to "okay". I find that somewhat more intuitive to the variant with an "enable-ports" property.

What do you think of this?

As a general concept, this kind of design seems OK to me.

The "port" child nodes I think should be named "pci at ..." given Mitch's comments, I think.

The port nodes probably need two entries in reg, given the following in our downstream driver:

Quoted 2 lines
        int rp_offset = 0;
        int ctrl_offset = AFI_PEX0_CTRL;

...

Quoted 6 lines
        for (port = 0; port < MAX_PCIE_SUPPORTED_PORTS; port++) {
                ctrl_offset += (port * 8);
                rp_offset = (rp_offset + 0x1000) * port;
                if (tegra_pcie.plat_data->port_status[port])
                        tegra_pcie_add_port(port, rp_offset, ctrl_offset);
        }
Quoted 2 lines

(which actually looks likely to be horribly buggy for port>1 and only accidentally correct for port==1, but anyway...)

Yeah, I currently have code that gets the port index and the reset register offset (ctrl_offset above) from the port address. It feels rather hackish, though.

Quoted 26 lines

But instead, I'd be tempted to make the top-level node say:

	#address-cells = <1>;
	#size-cells = <0>;

... so that the child nodes' reg is just the port ID. The parent node can calculate the addresses/offsets of the per-port registers within the PCIe controller's register space based on the ID using code roughly like what I quoted above:

	pci at 0 {
		reg = <0>;
		status = "disabled";
	};

	pci at 1 {
		reg = <0>;
		status = "disabled";
	};

That would save having to put 2 entries in the reg, and perhaps remove the need for any ranges property.

I think you also need a property to specify the exact port layout; the Tegra20 controller supports:

Quoted 7 lines

1 x4 port
2 x2 ports (you can choose to use only 1 of these I assume)

So just because only 1 of the ports is enabled, doesn't imply it's x4; it could still be x2.

Tegra30 has more options.

Both the upstream and downstream drivers currently hard-code this to dual and 411 (I assume that means 1x4, 2x1?) configurations for Tegra20 and Tegra30 respectively. Unfortunately the register AFI_PCIE_CONFIG isn't documented on Tegra20 at all and for Tegra30 lists only the valid configurations (see 28.4.1.5 PCIe CONFIG) but not the corresponding encodings.

Maybe a good name for the new property would be "num-lanes". I also wonder if this property would be better off in the parent node, which would make it easier to check for valid configurations. Otherwise the code would have to collect the settings of all the ports and check if the combination is valid. Then again, having num-lanes in the parent with one cell for each controller isn't very nice if each controller can be individually disabled.

One other thing: in addition to the device tree binding, this will all have to be represented in the platform data as well to support the legacy board definitions currently in the tree. But instead of adding all of these changes to the patch that converts the code to a driver, I'm thinking it might be better to split these additions off into one or more separate patches. Do you have any objections?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120613/aee9fdd4/attachment-0001.sig>

#84 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

Quoted 1 line · Thierry Reding

* Stephen Warren wrote:

...

Quoted 18 lines
Quoted 10 lines

I think you also need a property to specify the exact port layout; the Tegra20 controller supports:

1 x4 port 2 x2 ports (you can choose to use only 1 of these I assume)

So just because only 1 of the ports is enabled, doesn't imply it's x4; it could still be x2.

Tegra30 has more options.

Both the upstream and downstream drivers currently hard-code this to dual and 411 (I assume that means 1x4, 2x1?) configurations for Tegra20 and Tegra30 respectively. Unfortunately the register AFI_PCIE_CONFIG isn't documented on Tegra20 at all and for Tegra30 lists only the valid configurations (see 28.4.1.5 PCIe CONFIG) but not the corresponding encodings.

Quoted 7 lines

Maybe a good name for the new property would be "num-lanes". I also wonder if this property would be better off in the parent node, which would make it easier to check for valid configurations. Otherwise the code would have to collect the settings of all the ports and check if the combination is valid. Then again, having num-lanes in the parent with one cell for each controller isn't very nice if each controller can be individually disabled.

Indeed, since the register that controls this is in the main register set rather than the per-port register set, it does seem like a good idea to put the property in the main node, not the per-port node.

#85 lore raw

PATCH v2 7/10 ARM: tegra: pcie: Add device tree support

In reply to Thierry Reding

On 06/13/2012 12:34 AM, Thierry Reding wrote:
...

Quoted 6 lines

One other thing: in addition to the device tree binding, this will all have to be represented in the platform data as well to support the legacy board definitions currently in the tree. But instead of adding all of these changes to the patch that converts the code to a driver, I'm thinking it might be better to split these additions off into one or more separate patches. Do you have any objections?

So long as git bisect isn't broken for build- or run-time, that's just fine.

#86 lore raw

PATCH v2 8/10 ARM: tegra: harmony: Initialize regulators from DT

In reply to Thierry Reding

Device tree support for the TPS6586x PMU used on Harmony has recently been added. This commit adds the required device tree nodes to probe the PMU from the device tree.

---
Changes in v2:
- new patch

---
 arch/arm/boot/dts/tegra-harmony.dts    |   83 ++++++++++++++++++++++++++++++++
 arch/arm/mach-tegra/board-dt-tegra20.c |    6 ---
 2 files changed, 83 insertions(+), 6 deletions(-)
arch/arm/boot/dts/tegra-harmony.dts +83 -0
index f146dbf..c98aa2a 100644
@@ -275,6 +275,89 @@
 	i2c at 7000d000 {
 		status = "okay";
 		clock-frequency = <400000>;
+
+		tps6586x at 34 {
+			compatible = "ti,tps6586x";
+			reg = <0x34>;
+			interrupts = <0 88 0x4>;
+
+			#gpio-cells = <2>;
+			gpio-controller;
+
+			regulators {
+				sm0 {
+					regulator-min-microvolt = < 725000>;
+					regulator-max-microvolt = <1500000>;
+					regulator-boot-on;
+					regulator-always-on;
+				};
+
+				sm1 {
+					regulator-min-microvolt = < 725000>;
+					regulator-max-microvolt = <1500000>;
+					regulator-boot-on;
+					regulator-always-on;
+				};
+
+				sm2 {
+					regulator-min-microvolt = <3000000>;
+					regulator-max-microvolt = <4550000>;
+					regulator-boot-on;
+					regulator-always-on;
+				};
+
+				ldo0 {
+					regulator-name = "PCIE CLK";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				ldo1 {
+					regulator-min-microvolt = < 725000>;
+					regulator-max-microvolt = <1500000>;
+				};
+
+				ldo2 {
+					regulator-min-microvolt = < 725000>;
+					regulator-max-microvolt = <1500000>;
+				};
+
+				ldo3 {
+					regulator-min-microvolt = <1250000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				ldo4 {
+					regulator-min-microvolt = <1700000>;
+					regulator-max-microvolt = <2475000>;
+				};
+
+				ldo5 {
+					regulator-min-microvolt = <1250000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				ldo6 {
+					regulator-min-microvolt = <1250000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				ldo7 {
+					regulator-min-microvolt = <1250000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				ldo8 {
+					regulator-min-microvolt = <1250000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				ldo9 {
+					regulator-min-microvolt = <1250000>;
+					regulator-max-microvolt = <3300000>;
+				};
+			};
+		};
 	};
 
 	pmc {
arch/arm/mach-tegra/board-dt-tegra20.c +0 -6
index 0f29c05..a9a54e6 100644
@@ -136,12 +136,6 @@ static void __init harmony_init(void)
 {
 	int ret;
 
-	ret = harmony_regulator_init();
-	if (ret) {
-		pr_err("harmony_regulator_init() failed: %d\n", ret);
-		return;
-	}
-
 	ret = harmony_pcie_init();
 	if (ret)
 		pr_err("harmony_pcie_init() failed: %d\n", ret);
Signature · 1 line
1.7.10.4
#87 lore raw

PATCH v2 8/10 ARM: tegra: harmony: Initialize regulators from DT

Quoted 5 lines · Thierry Reding

Device tree support for the TPS6586x PMU used on Harmony has recently been added. This commit adds the required device tree nodes to probe the PMU from the device tree.

arch/arm/boot/dts/tegra-harmony.dts line 287

Quoted 10 lines
arch/arm/boot/dts/tegra-harmony.dts +9 -0
 
+		tps6586x at 34 {
+			compatible = "ti,tps6586x";
+			reg = <0x34>;
+			interrupts = <0 88 0x4>;
+
+			#gpio-cells = <2>;
+			gpio-controller;
+
+			regulators {

Per the TPS65911 discussion on regulator bindings, this node should have:

	#address-cells = <1>;
	#size-cells = <0>;

arch/arm/boot/dts/tegra-harmony.dts line 288

Quoted 1 line
arch/arm/boot/dts/tegra-harmony.dts +1 -0
+				sm0 {

Each of these nodes should be named regulator at 0, regulator at 1, etc.

Within each of these nodes, you need a matching reg property.

	reg = <0>;

and something to identify which regulator within the chip this node configurations, although I don't think we've reached a final decision on the property name.

See the the following for details:

http://www.spinics.net/lists/linux-tegra/msg05577.html

#88 lore raw

PATCH v2 8/10 ARM: tegra: harmony: Initialize regulators from DT

Quoted 30 lines · Stephen Warren
Quoted 5 lines · Thierry Reding

Device tree support for the TPS6586x PMU used on Harmony has recently been added. This commit adds the required device tree nodes to probe the PMU from the device tree.

arch/arm/boot/dts/tegra-harmony.dts line 287

Quoted 10 lines
arch/arm/boot/dts/tegra-harmony.dts +9 -0
 
+		tps6586x at 34 {
+			compatible = "ti,tps6586x";
+			reg = <0x34>;
+			interrupts = <0 88 0x4>;
+
+			#gpio-cells = <2>;
+			gpio-controller;
+
+			regulators {

Per the TPS65911 discussion on regulator bindings, this node should have:

	#address-cells = <1>;
	#size-cells = <0>;

arch/arm/boot/dts/tegra-harmony.dts line 288

Quoted 1 line
arch/arm/boot/dts/tegra-harmony.dts +1 -0
+				sm0 {

Each of these nodes should be named regulator at 0, regulator at 1, etc.

Within each of these nodes, you need a matching reg property.

	reg = <0>;
Quoted 7 lines

and something to identify which regulator within the chip this node configurations, although I don't think we've reached a final decision on the property name.

See the the following for details:

http://www.spinics.net/lists/linux-tegra/msg05577.html

Okay, I'll monitor that discussion and see what you end up with. I guess I'll have to update the tps6586x binding when that decision has been reached and add a patch to this series.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120612/d3908777/attachment.sig>

#89 lore raw

PATCH v2 8/10 ARM: tegra: harmony: Initialize regulators from DT

In reply to Thierry Reding

arch/arm/boot/dts/tegra-harmony.dts line 282

Quoted 10 lines · Thierry Reding

Device tree support for the TPS6586x PMU used on Harmony has recently been added. This commit adds the required device tree nodes to probe the PMU from the device tree.

arch/arm/boot/dts/tegra-harmony.dts +4 -0
 
+		tps6586x at 34 {
+			compatible = "ti,tps6586x";
+			reg = <0x34>;
+			interrupts = <0 88 0x4>;

I believe that should be interrupt 86 not 88.

#90 lore raw

PATCH v2 8/10 ARM: tegra: harmony: Initialize regulators from DT

Quoted 5 lines · Stephen Warren
Quoted 3 lines · Thierry Reding

Device tree support for the TPS6586x PMU used on Harmony has recently been added. This commit adds the required device tree nodes to probe the PMU from the device tree.

Quoted 8 lines

arch/arm/boot/dts/tegra-harmony.dts line 282

Quoted 6 lines
arch/arm/boot/dts/tegra-harmony.dts +4 -0
 
+		tps6586x at 34 {
+			compatible = "ti,tps6586x";
+			reg = <0x34>;
+			interrupts = <0 88 0x4>;

I believe that should be interrupt 86 not 88.

Yes, you're absolutely correct.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120622/4b5c3dc3/attachment.sig>

#91 lore raw

PATCH v2 9/10 ARM: tegra: harmony: Initialize PCIe from DT

In reply to Thierry Reding

With the device tree support in place, probe the PCIe controller from the device tree and remove the corresponding workaround in the board file.

---
Changes in v2:
- new patch

---
 arch/arm/boot/dts/tegra-harmony.dts    |   19 +++++++++++++++++--
 arch/arm/mach-tegra/board-dt-tegra20.c |   14 --------------
 2 files changed, 17 insertions(+), 16 deletions(-)
arch/arm/boot/dts/tegra-harmony.dts +17 -2
index c98aa2a..1dc907f 100644
@@ -276,7 +276,7 @@
 		status = "okay";
 		clock-frequency = <400000>;
 
-		tps6586x at 34 {
+		pmu: tps6586x at 34 {
 			compatible = "ti,tps6586x";
 			reg = <0x34>;
 			interrupts = <0 88 0x4>;
@@ -306,7 +306,7 @@
 					regulator-always-on;
 				};
 
-				ldo0 {
+				pci_clk_reg: ldo0 {
 					regulator-name = "PCIE CLK";
 					regulator-min-microvolt = <3300000>;
 					regulator-max-microvolt = <3300000>;
@@ -364,6 +364,21 @@
 		nvidia,invert-interrupt;
 	};
 
+	pci_vdd_reg: fixedregulator at 0 {
+		compatible = "regulator-fixed";
+		regulator-name = "PCIE VDD";
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1050000>;
+		enable-active-high;
+		gpio = <&pmu 2 0>;
+	};
+
+	pci {
+		pex-clk-supply = <&pci_clk_reg>;
+		vdd-supply = <&pci_vdd_reg>;
+		status = "okay";
+	};
+
 	usb at c5000000 {
 		status = "okay";
 	};
arch/arm/mach-tegra/board-dt-tegra20.c +0 -14
index a9a54e6..c7b6ae2 100644
@@ -131,17 +131,6 @@ static void __init trimslice_init(void)
 }
 #endif
 
-#ifdef CONFIG_MACH_HARMONY
-static void __init harmony_init(void)
-{
-	int ret;
-
-	ret = harmony_pcie_init();
-	if (ret)
-		pr_err("harmony_pcie_init() failed: %d\n", ret);
-}
-#endif
-
 #ifdef CONFIG_MACH_PAZ00
 static void __init paz00_init(void)
 {
@@ -156,9 +145,6 @@ static struct {
 #ifdef CONFIG_MACH_TRIMSLICE
 	{ "compulab,trimslice", trimslice_init },
 #endif
-#ifdef CONFIG_MACH_HARMONY
-	{ "nvidia,harmony", harmony_init },
-#endif
 #ifdef CONFIG_MACH_PAZ00
 	{ "compal,paz00", paz00_init },
 #endif
Signature · 1 line
1.7.10.4
#92 lore raw

PATCH v2 9/10 ARM: tegra: harmony: Initialize PCIe from DT

arch/arm/boot/dts/tegra-harmony.dts line 367

Quoted 7 lines · Thierry Reding

With the device tree support in place, probe the PCIe controller from the device tree and remove the corresponding workaround in the board file.

arch/arm/boot/dts/tegra-harmony.dts +1 -0
 
+	pci_vdd_reg: fixedregulator at 0 {

I think that'd usually just be "regulator at 0".

If you need the "@0" part to differentiate between multiple regulators, the node needs a reg property too:

	reg = <0 0>;

although then I wonder about putting the regulator under the root node, since the address wouldn't really make sense...

#93 lore raw

PATCH v2 9/10 ARM: tegra: harmony: Initialize PCIe from DT

Quoted 11 lines · Stephen Warren

arch/arm/boot/dts/tegra-harmony.dts line 367

Quoted 7 lines · Thierry Reding

With the device tree support in place, probe the PCIe controller from the device tree and remove the corresponding workaround in the board file.

arch/arm/boot/dts/tegra-harmony.dts +1 -0
 
+	pci_vdd_reg: fixedregulator at 0 {

I think that'd usually just be "regulator at 0".

Quoted 7 lines

If you need the "@0" part to differentiate between multiple regulators, the node needs a reg property too:

	reg = <0 0>;

although then I wonder about putting the regulator under the root node, since the address wouldn't really make sense...

Perhaps we should add a new "regulators" node under the root node to collect this kind of regulators that don't fit anywhere else. Looking at the code, something like this should work:

	/ {
		...

		regulators {
			compatible = "simple-bus";
			#address-cells = <1>;
			#size-cells = <0>;

			pci_vdd_reg: regulator at 0 {
				reg = <0>;
			};
		};
	};

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120612/4b13eac2/attachment.sig>

#94 lore raw

PATCH v2 9/10 ARM: tegra: harmony: Initialize PCIe from DT

Quoted 25 lines · Thierry Reding
Quoted 12 lines · Stephen Warren

arch/arm/boot/dts/tegra-harmony.dts line 367

Quoted 8 lines · Thierry Reding

With the device tree support in place, probe the PCIe controller from the device tree and remove the corresponding workaround in the board file.

arch/arm/boot/dts/tegra-harmony.dts +1 -0
 
+	pci_vdd_reg: fixedregulator at 0 {

I think that'd usually just be "regulator at 0".

Quoted 7 lines

If you need the "@0" part to differentiate between multiple regulators, the node needs a reg property too:

reg = <0 0>;

although then I wonder about putting the regulator under the root node, since the address wouldn't really make sense...

Perhaps we should add a new "regulators" node under the root node to collect this kind of regulators that don't fit anywhere else. Looking at the code, something like this should work:

Quoted 6 lines

/ { ...

regulators { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <0>;

pci_vdd_reg: regulator at 0 { reg = <0>; }; }; };

That seems like a good idea, and there's certainly precedent for doing exactly that in other ARM .dts files already.

To maintain .dts alphabetical sorting of non-addressed nodes, this new node should slot in just before the sound node, near the end of the file.

#95 lore raw

PATCH v2 10/10 ARM: tegra: trimslice: Initialize PCIe from DT

In reply to Thierry Reding

With the device tree support in place, probe the PCIe controller from the device tree and remove the corresponding workaround in the board file.

---
Changes in v2:
- new patch

---
 arch/arm/boot/dts/tegra-trimslice.dts  |    4 ++++
 arch/arm/mach-tegra/board-dt-tegra20.c |   18 ------------------
 2 files changed, 4 insertions(+), 18 deletions(-)
arch/arm/boot/dts/tegra-trimslice.dts +4 -0
index 9de5636..fc48f371 100644
@@ -274,6 +274,10 @@
 		};
 	};
 
+	pci {
+		status = "okay";
+	};
+
 	usb at c5000000 {
 		status = "okay";
 	};
arch/arm/mach-tegra/board-dt-tegra20.c +0 -18
index c7b6ae2..3a8b825 100644
@@ -116,21 +116,6 @@ static void __init tegra_dt_init(void)
 				tegra20_auxdata_lookup, NULL);
 }
 
-#ifdef CONFIG_MACH_TRIMSLICE
-static struct tegra_pcie_pdata trimslice_pcie_pdata = {
-	.enable_ports = {
-		[0] = true,
-		[1] = true,
-	},
-};
-
-static void __init trimslice_init(void)
-{
-	tegra_pcie_device.dev.platform_data = &trimslice_pcie_pdata;
-	platform_device_register(&tegra_pcie_device);
-}
-#endif
-
 #ifdef CONFIG_MACH_PAZ00
 static void __init paz00_init(void)
 {
@@ -142,9 +127,6 @@ static struct {
 	char *machine;
 	void (*init)(void);
 } board_init_funcs[] = {
-#ifdef CONFIG_MACH_TRIMSLICE
-	{ "compulab,trimslice", trimslice_init },
-#endif
 #ifdef CONFIG_MACH_PAZ00
 	{ "compal,paz00", paz00_init },
 #endif
Signature · 1 line
1.7.10.4