Re: [PATCH V6 06/27] PCI: tegra: Add PCIe Gen2 link speed support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Jun 18, 2019 at 11:31:45PM +0530, Manikanta Maddireddy wrote:
> Tegra124, Tegra132, Tegra210 and Tegra186 support Gen2 link speed. After
> PCIe link is up in Gen1, set target link speed as Gen2 and retrain link.
> Link switches to Gen2 speed if Gen2 capable end point is connected, else
> link stays in Gen1.
> 
> Per PCIe 4.0r0.9 sec 7.6.3.7 implementation note, driver need to wait for
> PCIe LTSSM to come back from recovery before retraining the link.
> 
> Signed-off-by: Manikanta Maddireddy <mmaddireddy@xxxxxxxxxx>
> Acked-by: Thierry Reding <treding@xxxxxxxxxx>
> ---
> V6: No change
> 
> V5: No change
> 
> V4: No change
> 
> V3: Added blank line after each while loop.
> 
> V2: Changed "for loop" to "while", to make it compact and handled coding
> style comments.
> 
>  drivers/pci/controller/pci-tegra.c | 64 ++++++++++++++++++++++++++++++
>  1 file changed, 64 insertions(+)
> 
> diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c
> index 5e9fcef5f8eb..5d19067f7193 100644
> --- a/drivers/pci/controller/pci-tegra.c
> +++ b/drivers/pci/controller/pci-tegra.c
> @@ -191,6 +191,8 @@
>  #define  RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE	0x20000000
>  #define  RP_LINK_CONTROL_STATUS_LINKSTAT_MASK	0x3fff0000
>  
> +#define RP_LINK_CONTROL_STATUS_2		0x000000b0
> +
>  #define PADS_CTL_SEL		0x0000009c
>  
>  #define PADS_CTL		0x000000a0
> @@ -226,6 +228,7 @@
>  #define PADS_REFCLK_CFG_DRVI_SHIFT		12 /* 15:12 */
>  
>  #define PME_ACK_TIMEOUT 10000
> +#define LINK_RETRAIN_TIMEOUT 100000 /* in usec */
>  
>  struct tegra_msi {
>  	struct msi_controller chip;
> @@ -2089,6 +2092,64 @@ static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port)
>  	return false;
>  }
>  
> +static void tegra_pcie_change_link_speed(struct tegra_pcie *pcie)
> +{
> +	struct device *dev = pcie->dev;
> +	struct tegra_pcie_port *port, *tmp;
> +	ktime_t deadline;
> +	u32 value;
> +
> +	list_for_each_entry_safe(port, tmp, &pcie->ports, list) {

And the reason to use the _safe version is ?

Lorenzo

> +		/*
> +		 * "Supported Link Speeds Vector" in "Link Capabilities 2"
> +		 * is not supported by Tegra. tegra_pcie_change_link_speed()
> +		 * is called only for Tegra chips which support Gen2.
> +		 * So there no harm if supported link speed is not verified.
> +		 */
> +		value = readl(port->base + RP_LINK_CONTROL_STATUS_2);
> +		value &= ~PCI_EXP_LNKSTA_CLS;
> +		value |= PCI_EXP_LNKSTA_CLS_5_0GB;
> +		writel(value, port->base + RP_LINK_CONTROL_STATUS_2);
> +
> +		/*
> +		 * Poll until link comes back from recovery to avoid race
> +		 * condition.
> +		 */
> +		deadline = ktime_add_us(ktime_get(), LINK_RETRAIN_TIMEOUT);
> +
> +		while (ktime_before(ktime_get(), deadline)) {
> +			value = readl(port->base + RP_LINK_CONTROL_STATUS);
> +			if ((value & PCI_EXP_LNKSTA_LT) == 0)
> +				break;
> +
> +			usleep_range(2000, 3000);
> +		}
> +
> +		if (value & PCI_EXP_LNKSTA_LT)
> +			dev_warn(dev, "PCIe port %u link is in recovery\n",
> +				 port->index);
> +
> +		/* Retrain the link */
> +		value = readl(port->base + RP_LINK_CONTROL_STATUS);
> +		value |= PCI_EXP_LNKCTL_RL;
> +		writel(value, port->base + RP_LINK_CONTROL_STATUS);
> +
> +		deadline = ktime_add_us(ktime_get(), LINK_RETRAIN_TIMEOUT);
> +
> +		while (ktime_before(ktime_get(), deadline)) {
> +			value = readl(port->base + RP_LINK_CONTROL_STATUS);
> +			if ((value & PCI_EXP_LNKSTA_LT) == 0)
> +				break;
> +
> +			usleep_range(2000, 3000);
> +		}
> +
> +		if (value & PCI_EXP_LNKSTA_LT)
> +			dev_err(dev, "failed to retrain link of port %u\n",
> +				port->index);
> +	}
> +}
> +
>  static void tegra_pcie_enable_ports(struct tegra_pcie *pcie)
>  {
>  	struct device *dev = pcie->dev;
> @@ -2113,6 +2174,9 @@ static void tegra_pcie_enable_ports(struct tegra_pcie *pcie)
>  		tegra_pcie_port_disable(port);
>  		tegra_pcie_port_free(port);
>  	}
> +
> +	if (pcie->soc->has_gen2)
> +		tegra_pcie_change_link_speed(pcie);
>  }
>  
>  static void tegra_pcie_disable_ports(struct tegra_pcie *pcie)
> -- 
> 2.17.1
> 



[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux