PCI: tegra: Add SW fixup for RAW violations [Linux 5.3]

This Linux kernel change "PCI: tegra: Add SW fixup for RAW violations" is included in the Linux 5.3 release. This change is authored by Manikanta Maddireddy <mmaddireddy [at] nvidia.com> on Tue Jun 18 23:31:53 2019 +0530. The commit for this change in Linux stable tree is 191cd6f (patch).

PCI: tegra: Add SW fixup for RAW violations

The logic which blocks read requests till AFI gets ACK for all outstanding
writes from memory controller does not behave correctly when number of
outstanding writes become more than 32 in Tegra124 and Tegra132.

SW fixup is to prevent writes from accumulating more than 32 by:

- limiting outstanding posted writes to 14
- modifying Gen1 and Gen2 UpdateFC timer frequency

UpdateFC timer frequency is equal to twice the value of register content
in nsec. These settings are recommended after stress testing with
different values.

Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Acked-by: Thierry Reding <treding@nvidia.com>

There are 34 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/pci/controller/pci-tegra.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c
index 609edcb..95e27c0 100644
--- a/drivers/pci/controller/pci-tegra.c
+++ b/drivers/pci/controller/pci-tegra.c
@@ -178,6 +178,13 @@

 #define AFI_PEXBIAS_CTRL_0     0x168

+#define RP_PRIV_XP_DL      0x00000494
+#define  RP_PRIV_XP_DL_GEN2_UPD_FC_TSHOLD  (0x1ff << 1)
+
+#define RP_RX_HDR_LIMIT        0x00000e00
+#define  RP_RX_HDR_LIMIT_PW_MASK   (0xff << 8)
+#define  RP_RX_HDR_LIMIT_PW        (0x0e << 8)
+
 #define RP_ECTL_2_R1   0x00000e84
 #define  RP_ECTL_2_R1_RX_CTLE_1C_MASK      0xffff

@@ -208,6 +215,7 @@
 #define  RP_VEND_XP_DL_UP          (1 << 30)
 #define  RP_VEND_XP_OPPORTUNISTIC_ACK      (1 << 27)
 #define  RP_VEND_XP_OPPORTUNISTIC_UPDATEFC (1 << 28)
+#define  RP_VEND_XP_UPDATE_FC_THRESHOLD_MASK   (0xff << 18)

 #define RP_VEND_CTL0   0x00000f44
 #define  RP_VEND_CTL0_DSK_RST_PULSE_WIDTH_MASK (0xf << 12)
@@ -301,6 +309,7 @@ struct tegra_pcie_soc {
    u32 tx_ref_sel;
    u32 pads_refclk_cfg0;
    u32 pads_refclk_cfg1;
+   u32 update_fc_threshold;
    bool has_pex_clkreq_en;
    bool has_pex_bias_ctrl;
    bool has_intr_prsnt_sense;
@@ -310,6 +319,7 @@ struct tegra_pcie_soc {
    bool program_uphy;
    bool update_clamp_threshold;
    bool program_deskew_time;
+   bool raw_violation_fixup;
    struct {
        struct {
            u32 rp_ectl_2_r1;
@@ -641,6 +651,23 @@ static void tegra_pcie_apply_sw_fixup(struct tegra_pcie_port *port)
        value |= RP_VEND_CTL0_DSK_RST_PULSE_WIDTH;
        writel(value, port->base + RP_VEND_CTL0);
    }
+
+   /* Fixup for read after write violation. */
+   if (soc->raw_violation_fixup) {
+       value = readl(port->base + RP_RX_HDR_LIMIT);
+       value &= ~RP_RX_HDR_LIMIT_PW_MASK;
+       value |= RP_RX_HDR_LIMIT_PW;
+       writel(value, port->base + RP_RX_HDR_LIMIT);
+
+       value = readl(port->base + RP_PRIV_XP_DL);
+       value |= RP_PRIV_XP_DL_GEN2_UPD_FC_TSHOLD;
+       writel(value, port->base + RP_PRIV_XP_DL);
+
+       value = readl(port->base + RP_VEND_XP);
+       value &= ~RP_VEND_XP_UPDATE_FC_THRESHOLD_MASK;
+       value |= soc->update_fc_threshold;
+       writel(value, port->base + RP_VEND_XP);
+   }
 }

 static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
@@ -2401,6 +2428,7 @@ static void tegra_pcie_disable_ports(struct tegra_pcie *pcie)
    .program_uphy = true,
    .update_clamp_threshold = false,
    .program_deskew_time = false,
+   .raw_violation_fixup = false,
    .ectl.enable = false,
 };

@@ -2427,6 +2455,7 @@ static void tegra_pcie_disable_ports(struct tegra_pcie *pcie)
    .program_uphy = true,
    .update_clamp_threshold = false,
    .program_deskew_time = false,
+   .raw_violation_fixup = false,
    .ectl.enable = false,
 };

@@ -2437,6 +2466,8 @@ static void tegra_pcie_disable_ports(struct tegra_pcie *pcie)
    .pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
    .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
    .pads_refclk_cfg0 = 0x44ac44ac,
+   /* FC threshold is bit[25:18] */
+   .update_fc_threshold = 0x03fc0000,
    .has_pex_clkreq_en = true,
    .has_pex_bias_ctrl = true,
    .has_intr_prsnt_sense = true,
@@ -2446,6 +2477,7 @@ static void tegra_pcie_disable_ports(struct tegra_pcie *pcie)
    .program_uphy = true,
    .update_clamp_threshold = true,
    .program_deskew_time = false,
+   .raw_violation_fixup = true,
    .ectl.enable = false,
 };

@@ -2465,6 +2497,7 @@ static void tegra_pcie_disable_ports(struct tegra_pcie *pcie)
    .program_uphy = true,
    .update_clamp_threshold = true,
    .program_deskew_time = true,
+   .raw_violation_fixup = false,
    .ectl = {
        .regs = {
            .rp_ectl_2_r1 = 0x0000000f,
@@ -2503,6 +2536,7 @@ static void tegra_pcie_disable_ports(struct tegra_pcie *pcie)
    .program_uphy = false,
    .update_clamp_threshold = false,
    .program_deskew_time = false,
+   .raw_violation_fixup = false,
    .ectl.enable = false,
 };

Leave a Reply

Your email address will not be published. Required fields are marked *