From d709d4695fd3740025068cc9225755255875f6ad Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Mon, 14 Aug 2023 16:34:13 -0600 Subject: pci: pcie-brcmstb: bring over some robustness improvements from Linux Since the initial U-Boot driver was ported here from Linux, the latter has had a few changes for robustness/stability. This patch brings over two of them: - Do not attempt to access the configuration space of a PCIe device if the link has gone down, as that will result in an asynchronous SError interrupt which will crash U-Boot. - Wait for the recommended 100ms after PERST# is deasserted. I sent this patch while debugging a crash involving PCIe, but these are unrelated improvements. I do not believe that this patch fixes any real-world bug. Signed-off-by: Sam Edwards --- drivers/pci/pcie_brcmstb.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/pcie_brcmstb.c b/drivers/pci/pcie_brcmstb.c index 1de28021138..a159952822b 100644 --- a/drivers/pci/pcie_brcmstb.c +++ b/drivers/pci/pcie_brcmstb.c @@ -223,6 +223,10 @@ static int brcm_pcie_config_address(const struct udevice *dev, pci_dev_t bdf, return 0; } + /* An access to our HW w/o link-up will cause a CPU Abort */ + if (!brcm_pcie_link_up(pcie)) + return -EINVAL; + /* For devices, write to the config space index register */ idx = PCIE_ECAM_OFFSET(pci_bus, pci_dev, pci_func, 0); @@ -505,6 +509,12 @@ static int brcm_pcie_probe(struct udevice *dev) clrbits_le32(pcie->base + PCIE_RGR1_SW_INIT_1, RGR1_SW_INIT_1_PERST_MASK); + /* + * Wait for 100ms after PERST# deassertion; see PCIe CEM specification + * sections 2.2, PCIe r5.0, 6.6.1. + */ + mdelay(100); + /* Give the RC/EP time to wake up, before trying to configure RC. * Intermittently check status for link-up, up to a total of 100ms. */ -- cgit v1.3.1 From 59bf0cdfa9a76cb6da7532a10584bcd40c3e3a00 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Wed, 16 Aug 2023 15:27:53 -0700 Subject: pci: pcie-brcmstb: do not rely on CLKREQ# signal When the Broadcom STB PCIe controller is initialized, it must be set into one of three CLKREQ# modes: "none"/"aspm"/"l1ss". The Linux driver, through today, hard-codes "aspm" since the vast majority of boards using this driver have a fixed PCIe bus with the CLKREQ# signal wired up. The Raspberry Pi CM4, however, can be connected to a plethora of PCIe devices, some of which do not connect the CLKREQ# line (they just leave it floating). So "aspm" mode is no longer appropriate in all cases. In Linux, there is a proposed patchset [1] to determine the proper mode. This doesn't really make sense in U-Boot's case, so we just change the assumption from "aspm" to "none" (which is always safe). This patch DOES resolve a real-world crash that occurs when U-Boot is running on a Raspberry Pi CM4 installed in slot 3 of a Turing Pi 2 cluster board. [1]: https://lore.kernel.org/all/20230428223500.23337-1-jim2101024@gmail.com/ Signed-off-by: Sam Edwards --- drivers/pci/pcie_brcmstb.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie_brcmstb.c b/drivers/pci/pcie_brcmstb.c index a159952822b..cd45f0bee9b 100644 --- a/drivers/pci/pcie_brcmstb.c +++ b/drivers/pci/pcie_brcmstb.c @@ -33,6 +33,9 @@ #define PCIE_RC_CFG_PRIV1_ID_VAL3 0x043c #define CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff +#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY 0x04dc +#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK 0xc00 + #define PCIE_RC_DL_MDIO_ADDR 0x1100 #define PCIE_RC_DL_MDIO_WR_DATA 0x1104 #define PCIE_RC_DL_MDIO_RD_DATA 0x1108 @@ -88,7 +91,6 @@ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8) #define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204 -#define PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2 #define PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000 #define PCIE_MSI_INTR2_CLR 0x4508 @@ -572,12 +574,18 @@ static int brcm_pcie_probe(struct udevice *dev) clrsetbits_le32(base + PCIE_RC_CFG_VENDOR_SPECIFIC_REG1, VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK, VENDOR_SPECIFIC_REG1_LITTLE_ENDIAN); + /* - * Refclk from RC should be gated with CLKREQ# input when ASPM L0s,L1 - * is enabled => setting the CLKREQ_DEBUG_ENABLE field to 1. + * We used to enable the CLKREQ# input here, but a few PCIe cards don't + * attach anything to the CLKREQ# line, so we shouldn't assume that + * it's connected and working. The controller does allow detecting + * whether the port on the other side of our link is/was driving this + * signal, so we could check before we assume. But because this signal + * is for power management, which doesn't make sense in a bootloader, + * let's instead just unadvertise ASPM support. */ - setbits_le32(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG, - PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK); + clrbits_le32(base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY, + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK); return 0; } -- cgit v1.3.1 From fa03568e46c9f4535b79e16faed4841ff7bfbe5b Mon Sep 17 00:00:00 2001 From: Maksim Kiselev Date: Fri, 18 Aug 2023 12:34:30 +0300 Subject: serial-uclass: reset gd->cur_serial_dev to NULL if serial not found Reset gd->cur_serial_dev pointer to avoid calling non-relocated code from relocated code if a serial driver is not found and CONFIG_REQUIRE_SERIAL_CONSOLE is disabled. Here is detailed explanation of what this patch is trying to fix. U-boot calls the serial_find_console_or_panic() function twice. The first console setup occurs before U-boot relocation in the serial_init(). This stage uses simple FDT parsing and assigns gd->cur_serial_dev to a "serial" device that lives in non-relocated code too. The second console setup after U-boot relocation(from serial_initialize()) may use full live DT (if OF_LIVE enabled) probe sequence with buses, clocks, resets, etc... And if the console setup fails at this step, than we should be caught by panic_str("No serial driver found"). But... If we disable CONFIG_REQUIRE_SERIAL_CONSOLE, than we return from serial_init() with gd->cur_serial_dev pointing to the "old"(non-relocated) serial device. And if this area, where "old" serial device is placed, is changed (e.g. Linux kernel may be relocated at this address), than we will get an unexpected crash on the next call of printf(). Signed-off-by: Maksim Kiselev --- drivers/serial/serial-uclass.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 067fae26145..e954f0189bb 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -151,6 +151,7 @@ static void serial_find_console_or_panic(void) #ifdef CONFIG_REQUIRE_SERIAL_CONSOLE panic_str("No serial driver found"); #endif + gd->cur_serial_dev = NULL; } #endif /* CONFIG_SERIAL_PRESENT */ -- cgit v1.3.1 From d223dcf31ad04e3b363770f2e20a36f1c7716568 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 23 Aug 2023 02:18:17 +0200 Subject: drivers/mtd/nvmxip: Trigger post bind as probe on driver level Perform all the block device creation only once, after the driver itself successfully bound. Do not do this in uclass post bind, as this might be triggered multiple times. For example the ut_dm_host test triggers this and triggers a memory leak that way, since there are now multiple block devices created using the blk_create_devicef() . To retain the old probe-on-boot behavior, set DM_FLAG_PROBE_AFTER_BIND flag in uclass post_bind callback, so the driver model would probe the driver at the right time. Rename the function as well, to match similar functions in other block-related subsystems, like the mmc one. Signed-off-by: Marek Vasut --- drivers/mtd/nvmxip/nvmxip-uclass.c | 18 +++++++----------- drivers/mtd/nvmxip/nvmxip_qspi.c | 1 + include/nvmxip.h | 12 ++++++++++++ 3 files changed, 20 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nvmxip/nvmxip-uclass.c b/drivers/mtd/nvmxip/nvmxip-uclass.c index 6d8eb177b50..36eb056c213 100644 --- a/drivers/mtd/nvmxip/nvmxip-uclass.c +++ b/drivers/mtd/nvmxip/nvmxip-uclass.c @@ -22,17 +22,7 @@ #define DEFAULT_LBA_SZ BIT(DEFAULT_LBA_SHIFT) -/** - * nvmxip_post_bind() - post binding treatments - * @dev: the NVMXIP device - * - * Create and probe a child block device. - * - * Return: - * - * 0 on success. Otherwise, failure - */ -static int nvmxip_post_bind(struct udevice *udev) +int nvmxip_probe(struct udevice *udev) { int ret; struct udevice *bdev = NULL; @@ -67,6 +57,12 @@ static int nvmxip_post_bind(struct udevice *udev) return 0; } +static int nvmxip_post_bind(struct udevice *udev) +{ + dev_or_flags(udev, DM_FLAG_PROBE_AFTER_BIND); + return 0; +} + UCLASS_DRIVER(nvmxip) = { .name = "nvmxip", .id = UCLASS_NVMXIP, diff --git a/drivers/mtd/nvmxip/nvmxip_qspi.c b/drivers/mtd/nvmxip/nvmxip_qspi.c index 7221fd1cb46..1bf0d311fe3 100644 --- a/drivers/mtd/nvmxip/nvmxip_qspi.c +++ b/drivers/mtd/nvmxip/nvmxip_qspi.c @@ -66,5 +66,6 @@ U_BOOT_DRIVER(nvmxip_qspi) = { .id = UCLASS_NVMXIP, .of_match = nvmxip_qspi_ids, .of_to_plat = nvmxip_qspi_of_to_plat, + .probe = nvmxip_probe, .plat_auto = sizeof(struct nvmxip_plat), }; diff --git a/include/nvmxip.h b/include/nvmxip.h index f4ef37725d2..726fffeb3e8 100644 --- a/include/nvmxip.h +++ b/include/nvmxip.h @@ -29,4 +29,16 @@ struct nvmxip_plat { lbaint_t lba; }; +/** + * nvmxip_bind() - post binding treatments + * @dev: the NVMXIP device + * + * Create and probe a child block device. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +int nvmxip_probe(struct udevice *udev); + #endif /* __DRIVER_NVMXIP_H__ */ -- cgit v1.3.1 From 16be2bc72e1c1ce188214b71ba5c7c9d990e6021 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 23 Aug 2023 02:18:18 +0200 Subject: drivers/mtd/nvmxip: Rework the read accessor to support 32bit systems Get rid of nvmxip_mmio_rawread() and just implement the readl()/readq() reader loop within nvmxip_blk_read(). Cast the destination buffer as needed and increment the read by either 4 or 8 bytes depending on if this is systemd with 32bit or 64bit physical address. Signed-off-by: Marek Vasut --- drivers/mtd/nvmxip/nvmxip.c | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nvmxip/nvmxip.c b/drivers/mtd/nvmxip/nvmxip.c index a359e3b4822..0bd98d64275 100644 --- a/drivers/mtd/nvmxip/nvmxip.c +++ b/drivers/mtd/nvmxip/nvmxip.c @@ -15,23 +15,6 @@ #include #include "nvmxip.h" -/** - * nvmxip_mmio_rawread() - read from the XIP flash - * @address: address of the data - * @value: pointer to where storing the value read - * - * Read raw data from the XIP flash. - * - * Return: - * - * Always return 0. - */ -static int nvmxip_mmio_rawread(const phys_addr_t address, u64 *value) -{ - *value = readq(address); - return 0; -} - /** * nvmxip_blk_read() - block device read operation * @dev: the block device @@ -49,15 +32,14 @@ static ulong nvmxip_blk_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcn { struct nvmxip_plat *plat = dev_get_plat(dev->parent); struct blk_desc *desc = dev_get_uclass_plat(dev); - /* number of the u64 words to read */ - u32 qwords = (blkcnt * desc->blksz) / sizeof(u64); + /* number of bytes to read */ + u32 size = blkcnt * desc->blksz; /* physical address of the first block to read */ phys_addr_t blkaddr = plat->phys_base + blknr * desc->blksz; - u64 *virt_blkaddr; - u64 *pdst = buffer; + void *virt_blkaddr; uint qdata_idx; - if (!pdst) + if (!buffer) return -EINVAL; log_debug("[%s]: reading from blknr: %lu , blkcnt: %lu\n", dev->name, blknr, blkcnt); @@ -66,12 +48,16 @@ static ulong nvmxip_blk_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcn /* assumption: the data is virtually contiguous */ - for (qdata_idx = 0 ; qdata_idx < qwords ; qdata_idx++) - nvmxip_mmio_rawread((phys_addr_t)(virt_blkaddr + qdata_idx), pdst++); - +#if IS_ENABLED(CONFIG_PHYS_64BIT) + for (qdata_idx = 0 ; qdata_idx < size; qdata_idx += sizeof(u64)) + *(u64 *)(buffer + qdata_idx) = readq(virt_blkaddr + qdata_idx); +#else + for (qdata_idx = 0 ; qdata_idx < size; qdata_idx += sizeof(u32)) + *(u32 *)(buffer + qdata_idx) = readl(virt_blkaddr + qdata_idx); +#endif log_debug("[%s]: src[0]: 0x%llx , dst[0]: 0x%llx , src[-1]: 0x%llx , dst[-1]: 0x%llx\n", dev->name, - *virt_blkaddr, + *(u64 *)virt_blkaddr, *(u64 *)buffer, *(u64 *)((u8 *)virt_blkaddr + desc->blksz * blkcnt - sizeof(u64)), *(u64 *)((u8 *)buffer + desc->blksz * blkcnt - sizeof(u64))); -- cgit v1.3.1 From 6539f71d1d85895afd60c68d039342447713ee50 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 23 Aug 2023 02:18:19 +0200 Subject: drivers/mtd/nvmxip: Print phys_addr_t without warnings on both 32bit and 64bit systems Cast the address such that it can be printed without warnings on both 32bit and 64bit systems. This really should use some better print formatter, but for the lack of it, do it this way. Signed-off-by: Marek Vasut --- drivers/mtd/nvmxip/nvmxip_qspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nvmxip/nvmxip_qspi.c b/drivers/mtd/nvmxip/nvmxip_qspi.c index 1bf0d311fe3..4d7471118a4 100644 --- a/drivers/mtd/nvmxip/nvmxip_qspi.c +++ b/drivers/mtd/nvmxip/nvmxip_qspi.c @@ -50,8 +50,8 @@ static int nvmxip_qspi_of_to_plat(struct udevice *dev) return -EINVAL; } - log_debug("[%s]: XIP device base addr: 0x%llx , lba_shift: %d , lbas: %lu\n", - dev->name, plat->phys_base, plat->lba_shift, plat->lba); + log_debug("[%s]: XIP device base addr: 0x%p , lba_shift: %d , lbas: %lu\n", + dev->name, (void *)(uintptr_t)plat->phys_base, plat->lba_shift, plat->lba); return 0; } -- cgit v1.3.1 From 8a4289ad727a1a6b47b5690e7b3c0fde64f3aebf Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 23 Aug 2023 02:18:20 +0200 Subject: drivers/mtd/nvmxip: Move sandbox_set_enable_memio() to test The sandbox_set_enable_memio() should only ever be set during sandbox testing, not within driver itself, move it back to test/ . Signed-off-by: Marek Vasut --- drivers/mtd/nvmxip/nvmxip-uclass.c | 4 ---- test/dm/nvmxip.c | 2 ++ 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nvmxip/nvmxip-uclass.c b/drivers/mtd/nvmxip/nvmxip-uclass.c index 36eb056c213..9a316d1de39 100644 --- a/drivers/mtd/nvmxip/nvmxip-uclass.c +++ b/drivers/mtd/nvmxip/nvmxip-uclass.c @@ -29,10 +29,6 @@ int nvmxip_probe(struct udevice *udev) char bdev_name[NVMXIP_BLKDEV_NAME_SZ + 1]; int devnum; -#if CONFIG_IS_ENABLED(SANDBOX64) - sandbox_set_enable_memio(true); -#endif - devnum = uclass_id_count(UCLASS_NVMXIP); snprintf(bdev_name, NVMXIP_BLKDEV_NAME_SZ, "blk#%d", devnum); diff --git a/test/dm/nvmxip.c b/test/dm/nvmxip.c index 89bf481f616..f0ad47d4efe 100644 --- a/test/dm/nvmxip.c +++ b/test/dm/nvmxip.c @@ -103,6 +103,8 @@ static int dm_test_nvmxip(struct unit_test_state *uts) void *buffer = NULL; unsigned long flashsz; + sandbox_set_enable_memio(true); + /* set the flash content first for both devices */ dm_nvmxip_flash_sanity(uts, 0, NULL); dm_nvmxip_flash_sanity(uts, 1, NULL); -- cgit v1.3.1