All of lore.kernel.org
 help / color / mirror / Atom feed
From: Stefan Roese <sr@denx.de>
To: u-boot@lists.denx.de
Cc: trini@konsulko.com, sjg@chromium.org, cchavva@marvell.com,
	awilliams@marvell.com
Subject: [PATCH v2 7/7] mips: octeon_nic23: Add PCIe FLR fixup via cyclic infrastructure
Date: Thu, 28 Jul 2022 09:09:34 +0200	[thread overview]
Message-ID: <20220728070934.641674-8-sr@denx.de> (raw)
In-Reply-To: <20220728070934.641674-1-sr@denx.de>

From: Aaron Williams <awilliams@marvell.com>

This patch adds a fixup function related to a PCIe FLR (Function Level
Reset) problem on the NIC23 PCIe board. This function is imported from
the Marvell Octeon 2013 U-Boot version as a (nearly) verbatim copy. It
uses the newly introduced cyclic infrastructure, so that this function
gets called every 100us, which is needed to detect this FLR issue.

Signed-off-by: Aaron Williams <awilliams@marvell.com>
Signed-off-by: Stefan Roese <sr@denx.de>
---
v2:
- No change

 board/Marvell/octeon_nic23/board.c | 197 +++++++++++++++++++++++++++++
 configs/octeon_nic23_defconfig     |   3 +
 2 files changed, 200 insertions(+)

diff --git a/board/Marvell/octeon_nic23/board.c b/board/Marvell/octeon_nic23/board.c
index 3e2c54444397..446fa5a659a8 100644
--- a/board/Marvell/octeon_nic23/board.c
+++ b/board/Marvell/octeon_nic23/board.c
@@ -3,8 +3,10 @@
  * Copyright (C) 2021-2022 Stefan Roese <sr@denx.de>
  */
 
+#include <cyclic.h>
 #include <dm.h>
 #include <ram.h>
+#include <time.h>
 #include <asm/gpio.h>
 
 #include <mach/octeon_ddr.h>
@@ -15,11 +17,90 @@
 #include <mach/cvmx-helper-cfg.h>
 #include <mach/cvmx-helper-util.h>
 #include <mach/cvmx-bgxx-defs.h>
+#include <mach/cvmx-dtx-defs.h>
 
 #include "board_ddr.h"
 
+/**
+ * cvmx_spem#_cfg_rd
+ *
+ * This register allows read access to the configuration in the PCIe core.
+ *
+ */
+union cvmx_spemx_cfg_rd {
+	u64 u64;
+	struct cvmx_spemx_cfg_rd_s {
+		u64 data                         : 32;
+		u64 addr                         : 32;
+	} s;
+	struct cvmx_spemx_cfg_rd_s            cn73xx;
+};
+
+/**
+ * cvmx_spem#_cfg_wr
+ *
+ * This register allows write access to the configuration in the PCIe core.
+ *
+ */
+union cvmx_spemx_cfg_wr {
+	u64 u64;
+	struct cvmx_spemx_cfg_wr_s {
+		u64 data                         : 32;
+		u64 addr                         : 32;
+	} s;
+	struct cvmx_spemx_cfg_wr_s            cn73xx;
+};
+
+/**
+ * cvmx_spem#_flr_pf_stopreq
+ *
+ * PF function level reset stop outbound requests register.
+ * Hardware automatically sets the STOPREQ bit for the PF when it enters a
+ * function level reset (FLR).  Software is responsible for clearing the STOPREQ
+ * bit but must not do so prior to hardware taking down the FLR, which could be
+ * as long as 100ms.  It may be appropriate for software to wait longer before clearing
+ * STOPREQ, software may need to drain deep DPI queues for example.
+ * Whenever SPEM receives a PF or child VF request mastered by CNXXXX over S2M (i.e. P or NP),
+ * when STOPREQ is set for the function, SPEM will discard the outgoing request
+ * before sending it to the PCIe core.  If a NP, SPEM will schedule an immediate
+ * SWI_RSP_ERROR completion for the request - no timeout is required.
+ * In both cases, SPEM()_DBG_PF()_INFO[P()_BMD_E] will be set and a error
+ * interrupt is generated.
+ *
+ * STOPREQ mimics the behavior of PCIEEP()_CFG001[ME] for outbound requests that will
+ * master the PCIe bus (P and NP).
+ *
+ * STOPREQ will have no effect on completions returned by CNXXXX over the S2M,
+ * nor on M2S traffic.
+ *
+ * When a PF()_STOPREQ is set, none of the associated
+ * PEM()_FLR_PF()_VF_STOPREQ[VF_STOPREQ] will be set.
+ *
+ * STOPREQ is reset when the MAC is reset, and is not reset after a chip soft reset.
+ */
+union cvmx_spemx_flr_pf_stopreq {
+	u64 u64;
+	struct cvmx_spemx_flr_pf_stopreq_s {
+		u64 reserved_3_63                : 61;
+		u64 pf2_stopreq                  : 1;
+		u64 pf1_stopreq                  : 1;
+		u64 pf0_stopreq                  : 1;
+	} s;
+	struct cvmx_spemx_flr_pf_stopreq_s    cn73xx;
+};
+
+#define CVMX_SPEMX_CFG_WR(offset)		0x00011800C0000028ull
+#define CVMX_SPEMX_CFG_RD(offset)		0x00011800C0000030ull
+#define CVMX_SPEMX_FLR_PF_STOPREQ(offset)	0x00011800C0000218ull
+
+#define DTX_SELECT_LTSSM		0x0
+#define DTX_SELECT_LTSSM_ENA		0x3ff
+#define LTSSM_L0			0x11
+
 #define NIC23_DEF_DRAM_FREQ		800
 
+static u32 pci_cfgspace_reg0[2] = { 0, 0 };
+
 static u8 octeon_nic23_cfg0_spd_values[512] = {
 	OCTEON_NIC23_CFG0_SPD_VALUES
 };
@@ -145,8 +226,118 @@ void board_configure_qlms(void)
 	      cvmx_qlm_measure_clock(4), cvmx_qlm_measure_clock(5));
 }
 
+/**
+ * If there is a PF FLR then the PCI EEPROM is not re-read.  In this case
+ * we need to re-program the vendor and device ID immediately after hardware
+ * completes FLR.
+ *
+ * PCI spec requires FLR to be completed within 100ms.  The user who triggered
+ * FLR expects hardware to finish FLR within 100ms, otherwise the user will
+ * end up reading DEVICE_ID incorrectly from the reset value.
+ * CN23XX exits FLR at any point between 66 and 99ms, so U-Boot has to wait
+ * 99ms to let hardware finish its part, then finish reprogramming the
+ * correct device ID before the end of 100ms.
+ *
+ * Note: this solution only works properly when there is no other activity
+ * within U-Boot for 100ms from the time FLR is triggered.
+ *
+ * This function gets called every 100usec.  If FLR happens during any
+ * other activity like bootloader/image update then it is possible that
+ * this function does not get called for more than the FLR period which will
+ * cause the PF device ID restore to happen after whoever initiated the FLR to
+ * read the incorrect device ID 0x9700 (reset value) instead of 0x9702
+ * (restored value).
+ */
+static void octeon_board_restore_pf(void *ctx)
+{
+	union cvmx_spemx_flr_pf_stopreq stopreq;
+	static bool start_initialized[2] = {false, false};
+	bool pf0_flag, pf1_flag;
+	u64 ltssm_bits;
+	const u64 pf_flr_wait_usecs = 99700;
+	u64 elapsed_usecs;
+	union cvmx_spemx_cfg_wr cfg_wr;
+	union cvmx_spemx_cfg_rd cfg_rd;
+	static u64 start_us[2];
+	int pf_num;
+
+	csr_wr(CVMX_DTX_SPEM_SELX(0), DTX_SELECT_LTSSM);
+	csr_rd(CVMX_DTX_SPEM_SELX(0));
+	csr_wr(CVMX_DTX_SPEM_ENAX(0), DTX_SELECT_LTSSM_ENA);
+	csr_rd(CVMX_DTX_SPEM_ENAX(0));
+	ltssm_bits = csr_rd(CVMX_DTX_SPEM_DATX(0));
+	if (((ltssm_bits >> 3) & 0x3f) != LTSSM_L0)
+		return;
+
+	stopreq.u64 = csr_rd(CVMX_SPEMX_FLR_PF_STOPREQ(0));
+	pf0_flag = stopreq.s.pf0_stopreq;
+	pf1_flag = stopreq.s.pf1_stopreq;
+	/* See if PF interrupt happened */
+	if (!(pf0_flag || pf1_flag))
+		return;
+
+	if (pf0_flag && !start_initialized[0]) {
+		start_initialized[0] = true;
+		start_us[0] = get_timer_us(0);
+	}
+
+	/* Store programmed PCIe DevID SPEM0 PF0 */
+	if (pf0_flag && !pci_cfgspace_reg0[0]) {
+		cfg_rd.s.addr = (0 << 24) | 0x0;
+		csr_wr(CVMX_SPEMX_CFG_RD(0), cfg_rd.u64);
+		cfg_rd.u64 = csr_rd(CVMX_SPEMX_CFG_RD(0));
+		pci_cfgspace_reg0[0] = cfg_rd.s.data;
+	}
+
+	if (pf1_flag && !start_initialized[1]) {
+		start_initialized[1] = true;
+		start_us[1] = get_timer_us(0);
+	}
+
+	/* Store programmed PCIe DevID SPEM0 PF1 */
+	if (pf1_flag && !pci_cfgspace_reg0[1]) {
+		cfg_rd.s.addr = (1 << 24) | 0x0;
+		csr_wr(CVMX_SPEMX_CFG_RD(0), cfg_rd.u64);
+		cfg_rd.u64 = csr_rd(CVMX_SPEMX_CFG_RD(0));
+		pci_cfgspace_reg0[1] = cfg_rd.s.data;
+	}
+
+	/* For PF, rewrite pci config space reg 0 */
+	for (pf_num = 0; pf_num < 2; pf_num++) {
+		if (!start_initialized[pf_num])
+			continue;
+
+		elapsed_usecs = get_timer_us(0) - start_us[pf_num];
+
+		if (elapsed_usecs > pf_flr_wait_usecs) {
+			/* Here, our measured FLR duration has passed;
+			 * check if device ID has been reset,
+			 * which indicates FLR completion (per MA team).
+			 */
+			cfg_rd.s.addr = (pf_num << 24) | 0x0;
+			csr_wr(CVMX_SPEMX_CFG_RD(0), cfg_rd.u64);
+			cfg_rd.u64 = csr_rd(CVMX_SPEMX_CFG_RD(0));
+			/* if DevID has NOT been reset, FLR is not yet
+			 * complete
+			 */
+			if (cfg_rd.s.data != pci_cfgspace_reg0[pf_num]) {
+				stopreq.s.pf0_stopreq = (pf_num == 0) ? 1 : 0;
+				stopreq.s.pf1_stopreq = (pf_num == 1) ? 1 : 0;
+				csr_wr(CVMX_SPEMX_FLR_PF_STOPREQ(0), stopreq.u64);
+
+				cfg_wr.u64 = 0;
+				cfg_wr.s.addr = (pf_num << 24) | 0;
+				cfg_wr.s.data = pci_cfgspace_reg0[pf_num];
+				csr_wr(CVMX_SPEMX_CFG_WR(0), cfg_wr.u64);
+				start_initialized[pf_num] = false;
+			}
+		}
+	}
+}
+
 int board_late_init(void)
 {
+	struct cyclic_struct *cyclic;
 	struct gpio_desc gpio = {};
 	ofnode node;
 
@@ -164,6 +355,12 @@ int board_late_init(void)
 
 	board_configure_qlms();
 
+	/* Register cyclic function for PCIe FLR fixup */
+	cyclic = cyclic_register(octeon_board_restore_pf, 100,
+				 "pcie_flr_fix", NULL);
+	if (!cyclic)
+		printf("Registering of cyclic function failed\n");
+
 	return 0;
 }
 
diff --git a/configs/octeon_nic23_defconfig b/configs/octeon_nic23_defconfig
index 95e98c1161db..098831e0b1ed 100644
--- a/configs/octeon_nic23_defconfig
+++ b/configs/octeon_nic23_defconfig
@@ -20,6 +20,8 @@ CONFIG_AHCI=y
 CONFIG_OF_BOARD_FIXUP=y
 CONFIG_SYS_CONSOLE_ENV_OVERWRITE=y
 # CONFIG_SYS_DEVICE_NULLDEV is not set
+CONFIG_CYCLIC=y
+CONFIG_CYCLIC_MAX_CPU_TIME_US=5000
 CONFIG_ARCH_MISC_INIT=y
 CONFIG_BOARD_EARLY_INIT_F=y
 CONFIG_BOARD_LATE_INIT=y
@@ -41,6 +43,7 @@ CONFIG_CMD_TIME=y
 CONFIG_CMD_EXT4=y
 CONFIG_CMD_FAT=y
 CONFIG_CMD_FS_GENERIC=y
+CONFIG_CMD_CYCLIC=y
 CONFIG_EFI_PARTITION=y
 CONFIG_ENV_IS_IN_SPI_FLASH=y
 CONFIG_TFTP_TSIZE=y
-- 
2.37.1


  parent reply	other threads:[~2022-07-28  7:11 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-28  7:09 [PATCH v2 0/7] Add support for cyclic function execution infrastruture Stefan Roese
2022-07-28  7:09 ` [PATCH v2 1/7] time: Import time_after64() and friends from Linux Stefan Roese
2022-07-28  7:09 ` [PATCH v2 2/7] cyclic: Add basic support for cyclic function execution infrastruture Stefan Roese
2022-07-28  7:09 ` [PATCH v2 3/7] cyclic: Integrate cyclic infrastructure into WATCHDOG_RESET Stefan Roese
2022-07-28  7:09 ` [PATCH v2 4/7] cyclic: Integrate cyclic functionality at bootup in board_r/f Stefan Roese
2022-07-28  7:09 ` [PATCH v2 5/7] cyclic: Add 'cyclic list' command Stefan Roese
2022-07-28  7:09 ` [PATCH v2 6/7] sandbox: Add cyclic demo function Stefan Roese
2022-07-28  7:09 ` Stefan Roese [this message]
2022-07-31  1:27 ` [PATCH v2 0/7] Add support for cyclic function execution infrastruture Simon Glass
2022-08-01  7:17   ` Stefan Roese
2022-08-01 12:22     ` Simon Glass
2022-08-01 12:40       ` Stefan Roese
2022-08-01 13:00         ` Simon Glass
2022-08-01 14:08           ` Stefan Roese
2022-08-01 19:13             ` Simon Glass
2022-08-01  7:54 ` Heinrich Schuchardt
2022-08-01  8:42   ` Stefan Roese

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220728070934.641674-8-sr@denx.de \
    --to=sr@denx.de \
    --cc=awilliams@marvell.com \
    --cc=cchavva@marvell.com \
    --cc=sjg@chromium.org \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.