Subject: [PATCH 10/14] PCI: tegra: Move PCIe driver to drivers/pci/host

From: [email-masked] (Stephen Warren)
Date: Thu, 10 Jan 2013 17:48:46 -0700

On 01/09/2013 01:43 PM, Thierry Reding wrote:
> Move the PCIe driver from arch/arm/mach-tegra into the drivers/pci/host
> directory. The motivation is to collect various host controller drivers
> in the same location in order to facilitate refactoring.
> 
> The Tegra PCIe driver has been largely rewritten, both in order to turn
> it into a proper platform driver and to add MSI (based on code by
> Krishna Kishore <[email-masked]>) as well as device tree support.

> diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c

>  static void __init trimslice_init(void)
>  {
>  #ifdef CONFIG_TEGRA_PCI
> -	int ret;
> -
> -	ret = tegra_pcie_init(true, true);
> -	if (ret)
> -		pr_err("tegra_pci_init() failed: %d\n", ret);
> +	platform_device_register(&tegra_pcie_device);

That struct doesn't actually exist anywhere; only an extern definition
is added (and that extern definition isn't removed by patch 14 either).

> diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig

> +config PCI_TEGRA
> +	bool "NVIDIA Tegra PCIe controller"
> +	depends on ARCH_TEGRA_2x_SOC

Perhaps depend on ARCH_TEGRA; that will save churn once this is ported
to Tegra30, and shouldn't cause any problems before then.

> diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c

> +#define AFI_INTR_CODE		0xb8
> +#define  AFI_INTR_CODE_MASK	0xf
> +#define  AFI_INTR_MASTER_ABORT	4
> +#define  AFI_INTR_LEGACY	6

Adding defines for at least some other codes here, would help further
below ...

> +static irqreturn_t tegra_pcie_isr(int irq, void *arg)

> +	if (code == AFI_INTR_MASTER_ABORT) {
> +		dev_dbg(pcie->dev, "%s, signature: %08x\n", err_msg[code],
> +			signature);
> +	} else
> +		dev_err(pcie->dev, "%s, signature: %08x\n", err_msg[code],
> +			signature);
> +
> +	if (code == 3 || code == 4 || code == 7) {

... i.e. here.

> +		u32 fpci = afi_readl(pcie, AFI_UPPER_FPCI_ADDRESS) & 0xff;
> +		u64 address = (u64)fpci << 32 | (signature & 0xfffffffc);
> +		dev_dbg(pcie->dev, "  FPCI address: %10llx\n", address);

I'd suggest making that dev_err(), or at least something higher than
debug, since the message indicating the error happened is dev_err(), so
the complete details may as well be available since they're small.

> +static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
> +{
> +	unsigned int timeout;
> +	unsigned long value;
> +
> +	/* enable dual controller and both ports */
> +	value = afi_readl(pcie, AFI_PCIE_CONFIG);
> +	value &= ~(AFI_PCIE_CONFIG_PCIEC0_DISABLE_DEVICE |
> +		   AFI_PCIE_CONFIG_PCIEC1_DISABLE_DEVICE |
> +		   AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK);
> +	value |= AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL;
> +	afi_writel(pcie, value, AFI_PCIE_CONFIG);

Eventually, we should probably derive the port enables from the state of
the root port DT nodes, so that we can disable some and presumably save
a little power. Also, I notice that the nvidia,num-lanes property isn't
implemented yet. Still, we can probably take care of this later.

> +static void tegra_pcie_power_off(struct tegra_pcie *pcie)

> +	if (!IS_ERR_OR_NULL(pcie->pex_clk_supply)) {

Hmm. I think we should make supplies mandatory; it doesn't make sense
for regulator support to be disabled on Tegra, and where a specific
board doesn't actually have a regulator, you're supposed to provide a
dummy fixed regulator so the driver doesn't have to care.

The same comment obviously applies to tegra_pcie_power_on() and wherever
regulator_get() happens.

> +static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)

> +	pcie->vdd_supply = devm_regulator_get(pcie->dev, "vdd");
> +	if (IS_ERR(pcie->vdd_supply))
> +		return PTR_ERR(pcie->vdd_supply);
> +
> +	pcie->pex_clk_supply = devm_regulator_get(pcie->dev, "pex-clk");
> +	if (IS_ERR(pcie->pex_clk_supply))
> +		return PTR_ERR(pcie->pex_clk_supply);

Oh, I guess the regulator_get() calls are already strict.

> +static int tegra_pcie_add_port(struct tegra_pcie *pcie, struct device_node *np)

> +	port = devm_kzalloc(pcie->dev, sizeof(*port), GFP_KERNEL);
> +	if (!port)
> +		return -ENOMEM;
> +
> +	INIT_LIST_HEAD(&port->list);
> +	port->index = index;
> +	port->pcie = pcie;
> +
> +	port->base = devm_request_and_ioremap(pcie->dev, &regs);
> +	if (!port->base)
> +		return -EADDRNOTAVAIL;
> +
> +	if (!tegra_pcie_port_check_link(port)) {
> +		dev_info(pcie->dev, "link %u down, ignoring\n", port->index);

Perhaps devm_kfree(port)? Not a big leak, but equally if you don't, it's
an unreferenced memory block.

> +		return -ENODEV;
> +	}
> +
> +	list_add_tail(&port->list, &pcie->ports);
> +
> +	return 0;
> +}