From 62649165cb02ab95b57360bb362886935f524f26 Mon Sep 17 00:00:00 2001 From: qianfan Zhao Date: Tue, 16 Nov 2021 09:35:38 +0800 Subject: [PATCH 01/13] lib: sparse: Make CHUNK_TYPE_RAW buffer aligned CHUNK_TYPE_RAW buffer is not aligned, and flash sparse images by fastboot will report "Misaligned operation" if DCACHE is enabled. Flashing Sparse Image CACHE: Misaligned operation at range [84000028, 84001028] CACHE: Misaligned operation at range [84001034, 84002034] CACHE: Misaligned operation at range [8401104c, 8401304c] Fix it Signed-off-by: qianfan Zhao Reviewed-by: Sean Anderson --- lib/image-sparse.c | 69 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 8 deletions(-) diff --git a/lib/image-sparse.c b/lib/image-sparse.c index d80fdbbf58..5ec0f94ab3 100644 --- a/lib/image-sparse.c +++ b/lib/image-sparse.c @@ -46,9 +46,66 @@ #include #include +#include static void default_log(const char *ignored, char *response) {} +static lbaint_t write_sparse_chunk_raw(struct sparse_storage *info, + lbaint_t blk, lbaint_t blkcnt, + void *data, + char *response) +{ + lbaint_t n = blkcnt, write_blks, blks = 0, aligned_buf_blks = 100; + uint32_t *aligned_buf = NULL; + + if (CONFIG_IS_ENABLED(SYS_DCACHE_OFF)) { + write_blks = info->write(info, blk, n, data); + if (write_blks < n) + goto write_fail; + + return write_blks; + } + + aligned_buf = memalign(ARCH_DMA_MINALIGN, info->blksz * aligned_buf_blks); + if (!aligned_buf) { + info->mssg("Malloc failed for: CHUNK_TYPE_RAW", response); + return -ENOMEM; + } + + while (blkcnt > 0) { + n = min(aligned_buf_blks, blkcnt); + memcpy(aligned_buf, data, n * info->blksz); + + /* write_blks might be > n due to NAND bad-blocks */ + write_blks = info->write(info, blk + blks, n, aligned_buf); + if (write_blks < n) { + free(aligned_buf); + goto write_fail; + } + + blks += write_blks; + data += n * info->blksz; + blkcnt -= n; + } + + free(aligned_buf); + return blks; + +write_fail: + if (IS_ERR_VALUE(write_blks)) { + printf("%s: Write failed, block #" LBAFU " [" LBAFU "] (%lld)\n", + __func__, blk + blks, n, (long long)write_blks); + info->mssg("flash write failure", response); + return write_blks; + } + + /* write_blks < n */ + printf("%s: Write failed, block #" LBAFU " [" LBAFU "]\n", + __func__, blk + blks, n); + info->mssg("flash write failure(incomplete)", response); + return -1; +} + int write_sparse_image(struct sparse_storage *info, const char *part_name, void *data, char *response) { @@ -152,15 +209,11 @@ int write_sparse_image(struct sparse_storage *info, return -1; } - blks = info->write(info, blk, blkcnt, data); - /* blks might be > blkcnt (eg. NAND bad-blocks) */ - if (blks < blkcnt) { - printf("%s: %s" LBAFU " [" LBAFU "]\n", - __func__, "Write failed, block #", - blk, blks); - info->mssg("flash write failure", response); + blks = write_sparse_chunk_raw(info, blk, blkcnt, + data, response); + if (blks < 0) return -1; - } + blk += blks; bytes_written += ((u64)blkcnt) * info->blksz; total_blocks += chunk_header->chunk_sz; From a398a51ccc68c0a7aee14f8328dc86a1a4cfba85 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sat, 20 Nov 2021 23:03:30 +0000 Subject: [PATCH 02/13] pci: Work around PCIe link training failures Attempt to handle cases with a downstream port of a PCIe switch where link training never completes and the link continues switching between speeds indefinitely with the data link layer never reaching the active state. It has been observed with a downstream port of the ASMedia ASM2824 Gen 3 switch wired to the upstream port of the Pericom PI7C9X2G304 Gen 2 switch, using a Delock Riser Card PCI Express x1 > 2 x PCIe x1 device, P/N 41433, wired to a SiFive HiFive Unmatched board. In this setup the switches are supposed to negotiate the link speed of preferably 5.0GT/s, falling back to 2.5GT/s. However the link continues oscillating between the two speeds, at the rate of 34-35 times per second, with link training reported repeatedly active ~84% of the time, e.g.: 02:03.0 PCI bridge [0604]: ASMedia Technology Inc. ASM2824 PCIe Gen3 Packet Switch [1b21:2824] (rev 01) (prog-if 00 [Normal decode]) [...] Bus: primary=02, secondary=05, subordinate=05, sec-latency=0 [...] Capabilities: [80] Express (v2) Downstream Port (Slot+), MSI 00 [...] LnkSta: Speed 5GT/s (downgraded), Width x1 (ok) TrErr- Train+ SlotClk+ DLActive- BWMgmt+ ABWMgmt- [...] LnkCtl2: Target Link Speed: 8GT/s, EnterCompliance- SpeedDis+, Selectable De-emphasis: -3.5dB Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS- Compliance De-emphasis: -6dB [...] Forcibly limiting the target link speed to 2.5GT/s with the upstream ASM2824 device makes the two switches communicate correctly however: 02:03.0 PCI bridge [0604]: ASMedia Technology Inc. ASM2824 PCIe Gen3 Packet Switch [1b21:2824] (rev 01) (prog-if 00 [Normal decode]) [...] Bus: primary=02, secondary=05, subordinate=09, sec-latency=0 [...] Capabilities: [80] Express (v2) Downstream Port (Slot+), MSI 00 [...] LnkSta: Speed 2.5GT/s (downgraded), Width x1 (ok) TrErr- Train- SlotClk+ DLActive+ BWMgmt- ABWMgmt- [...] LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance- SpeedDis+, Selectable De-emphasis: -3.5dB Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS- Compliance De-emphasis: -6dB [...] and then: 05:00.0 PCI bridge [0604]: Pericom Semiconductor PI7C9X2G304 EL/SL PCIe2 3-Port/4-Lane Packet Switch [12d8:2304] (rev 05) (prog-if 00 [Normal decode]) [...] Bus: primary=05, secondary=06, subordinate=09, sec-latency=0 [...] Capabilities: [c0] Express (v2) Upstream Port, MSI 00 [...] LnkSta: Speed 2.5GT/s (downgraded), Width x1 (downgraded) TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt- [...] LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis- Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS- Compliance De-emphasis: -6dB [...] Make use of this observation then and attempt to detect the inability to negotiate the link speed automatically, and then handle it by hand. Use the Data Link Layer Link Active status flag as the primary indicator of successful link speed negotiation, but given that the flag is optional by hardware to implement (the ASM2824 does have it though), resort to checking for the mandatory Link Bandwidth Management Status flag showing that the link speed or width has been changed in an attempt to correct unreliable link operation (the ASM2824 does set it too). If these checks indicate that link may not operate correctly, then poll the Data Link Layer Link Active status flag along with the Link Training flag for the duration of 200ms to see if the link has stabilised, that is either that the Data Link Layer Link Active status flag has been set or that Link Training has been inactive during at least the second half of the interval. If that has indicated failure, restrict the target speed to 2.5GT/s, request a link retrain and check again if the link has stabilised. If that does not work either, then restore the original speed setting and claim defeat, otherwise we are done. NB interestingly enough with the ASM2824 vs PI7C9X2G304 configuration referred above asking the ASM2824 to retrain with a higher target link speed once the 2.5GT/s speed has been negotiated makes the two devices successfully negotiate 5.0GT/s. Lifting the 2.5GT/s speed restriction would however prevent our workaround from working with an OS that issues a reset and that is unaware of the problem. This is because the devices would then try to negotiate a higher link speed from scratch and fail, while the sticky property of the Target Link Speed setting will keep the 2.5GT/s speed restriction across a reset. Keep the 2.5GT/s speed restriction then, conservatively, if functional once applied. Signed-off-by: Maciej W. Rozycki Reviewed-by: Stefan Roese --- drivers/pci/pci_auto.c | 170 +++++++++++++++++++++++++++++++++++++++++ include/pci.h | 21 ++++- 2 files changed, 189 insertions(+), 2 deletions(-) diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c index c0acf33139..c7968926a1 100644 --- a/drivers/pci/pci_auto.c +++ b/drivers/pci/pci_auto.c @@ -5,6 +5,7 @@ * Author: Matt Porter * * Copyright 2000 MontaVista Software Inc. + * Copyright (c) 2021 Maciej W. Rozycki */ #include @@ -12,6 +13,7 @@ #include #include #include +#include #include "pci_internal.h" /* the user can define CONFIG_SYS_PCI_CACHE_LINE_SIZE to avoid problems */ @@ -180,6 +182,168 @@ static void dm_pciauto_setup_device(struct udevice *dev, dm_pci_write_config8(dev, PCI_LATENCY_TIMER, 0x80); } +/* + * Check if the link of a downstream PCIe port operates correctly. + * + * For that check if the optional Data Link Layer Link Active status gets + * on within a 200ms period or failing that wait until the completion of + * that period and check if link training has shown the completed status + * continuously throughout the second half of that period. + * + * Observation with the ASMedia ASM2824 Gen 3 switch indicates it takes + * 11-44ms to indicate the Data Link Layer Link Active status at 2.5GT/s, + * though it may take a couple of link training iterations. + */ +static bool dm_pciauto_exp_link_stable(struct udevice *dev, int pcie_off) +{ + u64 loops = 0, trcount = 0, ntrcount = 0, flips = 0; + bool dllla, lnktr, plnktr; + u16 exp_lnksta; + pci_dev_t bdf; + u64 end; + + dm_pci_read_config16(dev, pcie_off + PCI_EXP_LNKSTA, &exp_lnksta); + plnktr = !!(exp_lnksta & PCI_EXP_LNKSTA_LT); + + end = get_ticks() + usec_to_tick(200000); + do { + dm_pci_read_config16(dev, pcie_off + PCI_EXP_LNKSTA, + &exp_lnksta); + dllla = !!(exp_lnksta & PCI_EXP_LNKSTA_DLLLA); + lnktr = !!(exp_lnksta & PCI_EXP_LNKSTA_LT); + + flips += plnktr ^ lnktr; + if (lnktr) { + ntrcount = 0; + trcount++; + } else { + ntrcount++; + } + loops++; + + plnktr = lnktr; + } while (!dllla && get_ticks() < end); + + bdf = dm_pci_get_bdf(dev); + debug("PCI Autoconfig: %02x.%02x.%02x: Fixup link: DL active: %u; " + "%3llu flips, %6llu loops of which %6llu while training, " + "final %6llu stable\n", + PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), + (unsigned int)dllla, + (unsigned long long)flips, (unsigned long long)loops, + (unsigned long long)trcount, (unsigned long long)ntrcount); + + return dllla || ntrcount >= loops / 2; +} + +/* + * Retrain the link of a downstream PCIe port by hand if necessary. + * + * This is needed at least where a downstream port of the ASMedia ASM2824 + * Gen 3 switch is wired to the upstream port of the Pericom PI7C9X2G304 + * Gen 2 switch, and observed with the Delock Riser Card PCI Express x1 > + * 2 x PCIe x1 device, P/N 41433, plugged into the SiFive HiFive Unmatched + * board. + * + * In such a configuration the switches are supposed to negotiate the link + * speed of preferably 5.0GT/s, falling back to 2.5GT/s. However the link + * continues switching between the two speeds indefinitely and the data + * link layer never reaches the active state, with link training reported + * repeatedly active ~84% of the time. Forcing the target link speed to + * 2.5GT/s with the upstream ASM2824 device makes the two switches talk to + * each other correctly however. And more interestingly retraining with a + * higher target link speed afterwards lets the two successfully negotiate + * 5.0GT/s. + * + * As this can potentially happen with any device and is cheap in the case + * of correctly operating hardware, let's do it for all downstream ports, + * for root complexes, PCIe switches and PCI/PCI-X to PCIe bridges. + * + * First check if automatic link training may have failed to complete, as + * indicated by the optional Data Link Layer Link Active status being off + * and the Link Bandwidth Management Status indicating that hardware has + * changed the link speed or width in an attempt to correct unreliable + * link operation. If this is the case, then check if the link operates + * correctly by seeing whether it is being trained excessively. If it is, + * then conclude the link is broken. + * + * In that case restrict the speed to 2.5GT/s, observing that the Target + * Link Speed field is sticky and therefore the link will stay restricted + * even after a device reset is later made by an OS that is unaware of the + * problem. With the speed restricted request that the link be retrained + * and check again if the link operates correctly. If not, then set the + * Target Link Speed back to the original value. + * + * This requires the presence of the Link Control 2 register, so make sure + * the PCI Express Capability Version is at least 2. Also don't try, for + * obvious reasons, to limit the speed if 2.5GT/s is the only link speed + * supported. + */ +static void dm_pciauto_exp_fixup_link(struct udevice *dev, int pcie_off) +{ + u16 exp_lnksta, exp_lnkctl, exp_lnkctl2; + u16 exp_flags, exp_type, exp_version; + u32 exp_lnkcap; + pci_dev_t bdf; + + dm_pci_read_config16(dev, pcie_off + PCI_EXP_FLAGS, &exp_flags); + exp_version = exp_flags & PCI_EXP_FLAGS_VERS; + if (exp_version < 2) + return; + + exp_type = (exp_flags & PCI_EXP_FLAGS_TYPE) >> 4; + switch (exp_type) { + case PCI_EXP_TYPE_ROOT_PORT: + case PCI_EXP_TYPE_DOWNSTREAM: + case PCI_EXP_TYPE_PCIE_BRIDGE: + break; + default: + return; + } + + dm_pci_read_config32(dev, pcie_off + PCI_EXP_LNKCAP, &exp_lnkcap); + if ((exp_lnkcap & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB) + return; + + dm_pci_read_config16(dev, pcie_off + PCI_EXP_LNKSTA, &exp_lnksta); + if ((exp_lnksta & (PCI_EXP_LNKSTA_LBMS | PCI_EXP_LNKSTA_DLLLA)) != + PCI_EXP_LNKSTA_LBMS) + return; + + if (dm_pciauto_exp_link_stable(dev, pcie_off)) + return; + + bdf = dm_pci_get_bdf(dev); + printf("PCI Autoconfig: %02x.%02x.%02x: " + "Downstream link non-functional\n", + PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); + printf("PCI Autoconfig: %02x.%02x.%02x: " + "Retrying with speed restricted to 2.5GT/s...\n", + PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); + + dm_pci_read_config16(dev, pcie_off + PCI_EXP_LNKCTL, &exp_lnkctl); + dm_pci_read_config16(dev, pcie_off + PCI_EXP_LNKCTL2, &exp_lnkctl2); + + dm_pci_write_config16(dev, pcie_off + PCI_EXP_LNKCTL2, + (exp_lnkctl2 & ~PCI_EXP_LNKCTL2_TLS) | + PCI_EXP_LNKCTL2_TLS_2_5GT); + dm_pci_write_config16(dev, pcie_off + PCI_EXP_LNKCTL, + exp_lnkctl | PCI_EXP_LNKCTL_RL); + + if (dm_pciauto_exp_link_stable(dev, pcie_off)) { + printf("PCI Autoconfig: %02x.%02x.%02x: Succeeded!\n", + PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); + } else { + printf("PCI Autoconfig: %02x.%02x.%02x: Failed!\n", + PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); + + dm_pci_write_config16(dev, pcie_off + PCI_EXP_LNKCTL2, + exp_lnkctl2); + dm_pci_write_config16(dev, pcie_off + PCI_EXP_LNKCTL, + exp_lnkctl | PCI_EXP_LNKCTL_RL); + } +} + void dm_pciauto_prescan_setup_bridge(struct udevice *dev, int sub_bus) { struct pci_region *pci_mem; @@ -189,6 +353,7 @@ void dm_pciauto_prescan_setup_bridge(struct udevice *dev, int sub_bus) u8 io_32; struct udevice *ctlr = pci_get_controller(dev); struct pci_controller *ctlr_hose = dev_get_uclass_priv(ctlr); + int pcie_off; pci_mem = ctlr_hose->pci_mem; pci_prefetch = ctlr_hose->pci_prefetch; @@ -275,6 +440,11 @@ void dm_pciauto_prescan_setup_bridge(struct udevice *dev, int sub_bus) } } + /* For PCIe devices see if we need to retrain the link by hand */ + pcie_off = dm_pci_find_capability(dev, PCI_CAP_ID_EXP); + if (pcie_off) + dm_pciauto_exp_fixup_link(dev, pcie_off); + /* Enable memory and I/O accesses, enable bus master */ dm_pci_write_config16(dev, PCI_COMMAND, cmdstat | PCI_COMMAND_MASTER); } diff --git a/include/pci.h b/include/pci.h index 0ea41a7e1b..ad1171b0a2 100644 --- a/include/pci.h +++ b/include/pci.h @@ -5,6 +5,7 @@ * * (C) Copyright 2002 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Copyright (c) 2021 Maciej W. Rozycki */ #ifndef _PCI_H @@ -475,16 +476,24 @@ /* PCI Express capabilities */ #define PCI_EXP_FLAGS 2 /* Capabilities register */ +#define PCI_EXP_FLAGS_VERS 0x000f /* Capability Version */ #define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */ -#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */ +#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */ +#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */ +#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIe Bridge */ #define PCI_EXP_DEVCAP 4 /* Device capabilities */ #define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */ #define PCI_EXP_DEVCTL 8 /* Device Control */ #define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR */ #define PCI_EXP_LNKCAP 12 /* Link Capabilities */ #define PCI_EXP_LNKCAP_SLS 0x0000000f /* Supported Link Speeds */ +#define PCI_EXP_LNKCAP_SLS_2_5GB 0x00000001 /* LNKCAP2 SLS Vector bit 0 */ +#define PCI_EXP_LNKCAP_SLS_5_0GB 0x00000002 /* LNKCAP2 SLS Vector bit 1 */ +#define PCI_EXP_LNKCAP_SLS_8_0GB 0x00000003 /* LNKCAP2 SLS Vector bit 2 */ #define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */ #define PCI_EXP_LNKCAP_DLLLARC 0x00100000 /* Data Link Layer Link Active Reporting Capable */ +#define PCI_EXP_LNKCTL 16 /* Link Control */ +#define PCI_EXP_LNKCTL_RL 0x0020 /* Retrain Link */ #define PCI_EXP_LNKSTA 18 /* Link Status */ #define PCI_EXP_LNKSTA_CLS 0x000f /* Current Link Speed */ #define PCI_EXP_LNKSTA_CLS_2_5GB 0x0001 /* Current Link Speed 2.5GT/s */ @@ -492,7 +501,9 @@ #define PCI_EXP_LNKSTA_CLS_8_0GB 0x0003 /* Current Link Speed 8.0GT/s */ #define PCI_EXP_LNKSTA_NLW 0x03f0 /* Negotiated Link Width */ #define PCI_EXP_LNKSTA_NLW_SHIFT 4 /* start of NLW mask in link status */ +#define PCI_EXP_LNKSTA_LT 0x0800 /* Link Training */ #define PCI_EXP_LNKSTA_DLLLA 0x2000 /* Data Link Layer Link Active */ +#define PCI_EXP_LNKSTA_LBMS 0x4000 /* Link Bandwidth Management Status */ #define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ #define PCI_EXP_SLTCAP_PSN 0xfff80000 /* Physical Slot Number */ #define PCI_EXP_RTCTL 28 /* Root Control */ @@ -503,8 +514,14 @@ #define PCI_EXP_DEVCAP2_ARI 0x00000020 /* ARI Forwarding Supported */ #define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ #define PCI_EXP_DEVCTL2_ARI 0x0020 /* Alternative Routing-ID */ - +#define PCI_EXP_LNKCAP2 44 /* Link Capability 2 */ +#define PCI_EXP_LNKCAP2_SLS 0x000000fe /* Supported Link Speeds Vector */ #define PCI_EXP_LNKCTL2 48 /* Link Control 2 */ +#define PCI_EXP_LNKCTL2_TLS 0x000f /* Target Link Speed */ +#define PCI_EXP_LNKCTL2_TLS_2_5GT 0x0001 /* Target Link Speed 2.5GT/s */ +#define PCI_EXP_LNKCTL2_TLS_5_0GT 0x0002 /* Target Link Speed 5.0GT/s */ +#define PCI_EXP_LNKCTL2_TLS_8_0GT 0x0003 /* Target Link Speed 8.0GT/s */ + /* Single Root I/O Virtualization Registers */ #define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */ #define PCI_SRIOV_CTRL 0x08 /* SR-IOV Control */ From 0a4512b5fba8018a3c57ed5be67c5565f5860864 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 30 Nov 2021 15:33:53 +0100 Subject: [PATCH 03/13] test: test_lsblk: Mark as sandbox specific This test checks for output specific to the sandbox blk device "sandbox_host_blk", mark it as sandbox specific. Signed-off-by: Patrick Delaunay --- test/py/tests/test_lsblk.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/py/tests/test_lsblk.py b/test/py/tests/test_lsblk.py index 40ffe01263..a719a48e6e 100644 --- a/test/py/tests/test_lsblk.py +++ b/test/py/tests/test_lsblk.py @@ -4,6 +4,7 @@ import pytest +@pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('blk') @pytest.mark.buildconfigspec('cmd_lsblk') def test_lsblk(u_boot_console): From d17ab6e1289b1d705c75de8a2351218962fb7352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Thu, 9 Dec 2021 11:06:39 +0100 Subject: [PATCH 04/13] nvme: Do not allocate 8kB buffer on stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling 'nvme scan' followed by 'nvme detail' crashes U-Boot on Turris Omnia with the following error: undefined instruction pc : [<0a000000>] lr : [<7ff80bfc>] reloc pc : [<8a8c0000>] lr : [<00840bfc>] sp : 7fb2b908 ip : 0000002a fp : 02000000 r10: 04000000 r9 : 7fb2fed0 r8 : e1000000 r7 : 0c000000 r6 : 03000000 r5 : 06000000 r4 : 01000000 r3 : 7fb30928 r2 : 7fb30928 r1 : 00000000 r0 : 00000000 Flags: nZCv IRQs off FIQs off Mode SVC_32 Code: 0f0fb4f0 0f0fb4f0 0f0fb4f0 0f0fb4f0 (f0f04b0f) Resetting CPU ... This happens when nvme_print_info() tries to return to the caller. It looks like this error is caused by trying to allocate 8 KiB of memory on the stack by the two uses of ALLOC_CACHE_ALIGN_BUFFER(). Use malloc_cache_aligned() to allocate this memory dynamically instead. This fixes 'nvme detail' on Turris Omnia. Note that similar change was applied to file drivers/nvme/nvme.c in past by commit 2f83481dff9c ("nvme: use page-aligned buffer for identify command"). Signed-off-by: Pali Rohár Signed-off-by: Marek Behún --- drivers/nvme/nvme_show.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/nvme/nvme_show.c b/drivers/nvme/nvme_show.c index 15e459da1a..72cbac82bc 100644 --- a/drivers/nvme/nvme_show.c +++ b/drivers/nvme/nvme_show.c @@ -106,24 +106,41 @@ int nvme_print_info(struct udevice *udev) { struct nvme_ns *ns = dev_get_priv(udev); struct nvme_dev *dev = ns->dev; - ALLOC_CACHE_ALIGN_BUFFER(char, buf_ns, sizeof(struct nvme_id_ns)); - struct nvme_id_ns *id = (struct nvme_id_ns *)buf_ns; - ALLOC_CACHE_ALIGN_BUFFER(char, buf_ctrl, sizeof(struct nvme_id_ctrl)); - struct nvme_id_ctrl *ctrl = (struct nvme_id_ctrl *)buf_ctrl; + struct nvme_id_ctrl *ctrl; + struct nvme_id_ns *id; + int ret = 0; - if (nvme_identify(dev, 0, 1, (dma_addr_t)(long)ctrl)) - return -EIO; + ctrl = memalign(dev->page_size, sizeof(struct nvme_id_ctrl)); + if (!ctrl) + return -ENOMEM; + + if (nvme_identify(dev, 0, 1, (dma_addr_t)(long)ctrl)) { + ret = -EIO; + goto free_ctrl; + } print_optional_admin_cmd(le16_to_cpu(ctrl->oacs), ns->devnum); print_optional_nvm_cmd(le16_to_cpu(ctrl->oncs), ns->devnum); print_format_nvme_attributes(ctrl->fna, ns->devnum); - if (nvme_identify(dev, ns->ns_id, 0, (dma_addr_t)(long)id)) - return -EIO; + id = memalign(dev->page_size, sizeof(struct nvme_id_ns)); + if (!id) { + ret = -ENOMEM; + goto free_ctrl; + } + + if (nvme_identify(dev, ns->ns_id, 0, (dma_addr_t)(long)id)) { + ret = -EIO; + goto free_id; + } print_formats(id, ns); print_data_protect_cap(id->dpc, ns->devnum); print_metadata_cap(id->mc, ns->devnum); - return 0; +free_id: + free(id); +free_ctrl: + free(ctrl); + return ret; } From 2f3e8d6a86cbeb45d387d47fa71220885ed7e481 Mon Sep 17 00:00:00 2001 From: Hou Zhiqiang Date: Wed, 15 Dec 2021 14:23:52 +0800 Subject: [PATCH 05/13] checkpatch: report ERROR only on disabling of fdt and initrd relocation Let the check pass when patches have these patterns in their context. Signed-off-by: Hou Zhiqiang --- scripts/checkpatch.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 5696d3a5f3..cf59e2bb70 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2617,7 +2617,7 @@ sub u_boot_line { } # Do not disable fdt / initrd relocation - if ($rawline =~ /.*(fdt|initrd)_high=0xffffffff/) { + if ($rawline =~ /^\+.*(fdt|initrd)_high=0xffffffff/) { ERROR("DISABLE_FDT_OR_INITRD_RELOC", "fdt or initrd relocation disabled at boot time\n" . $herecurr); } From 499f18446d2ceb4a48730e9ef3111bcbd9fae9de Mon Sep 17 00:00:00 2001 From: Samuel Dionne-Riel Date: Mon, 20 Dec 2021 18:19:16 -0500 Subject: [PATCH 06/13] lib: export vsscanf The function was missing from exports, even though it loooks like the intent of the implementation in sscanf.c was to have it exported. Signed-off-by: Samuel Dionne-Riel Cc: Simon Glass Reviewed-by: Simon Glass --- include/vsprintf.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/vsprintf.h b/include/vsprintf.h index b474630146..8bfafa0d33 100644 --- a/include/vsprintf.h +++ b/include/vsprintf.h @@ -307,6 +307,14 @@ char *strmhz(char *buf, unsigned long hz); */ void str_to_upper(const char *in, char *out, size_t len); +/** + * vsscanf - Unformat a buffer into a list of arguments + * @buf: input buffer + * @fmt: format of buffer + * @args: arguments + */ +int vsscanf(const char *inp, char const *fmt0, va_list ap); + /** * sscanf - Unformat a buffer into a list of arguments * @buf: input buffer From 4a05497a8ce9292017b7a5d0e48ecc45705a0a4b Mon Sep 17 00:00:00 2001 From: Samuel Dionne-Riel Date: Mon, 20 Dec 2021 18:23:45 -0500 Subject: [PATCH 07/13] cmd: adc: Report return value on error Reporting the return value should always be done on error conditions, this way the developer can start debugging issues with more knowledge in-hand. Signed-off-by: Samuel Dionne-Riel --- cmd/adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/adc.c b/cmd/adc.c index 16f914a030..75739bc8ee 100644 --- a/cmd/adc.c +++ b/cmd/adc.c @@ -81,8 +81,8 @@ static int do_adc_single(struct cmd_tbl *cmdtp, int flag, int argc, ret = adc_channel_single_shot(argv[1], simple_strtol(argv[2], NULL, 0), &data); if (ret) { - printf("Error getting single shot for device %s channel %s\n", - argv[1], argv[2]); + printf("Error getting single shot for device %s channel %s (ret=%d)\n", + argv[1], argv[2], ret); return CMD_RET_FAILURE; } From 36a3b4ed5632d8da13e3b89796cfdd0683021224 Mon Sep 17 00:00:00 2001 From: Joel Peshkin Date: Mon, 20 Dec 2021 20:15:47 -0800 Subject: [PATCH 08/13] BRCMNAND: Fix reporting of uncorrectable errors on subpages during page read Previously, a subpage with an uncorrectable error followed by a subpage with a correctable error would return an erroneous correctable status. Signed-off-by: Joel Peshkin Cc: Simon Glass Reviewed-by: Simon Glass --- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index f8434ca88d..74c9348f7f 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -1632,7 +1632,7 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip, mtd->oobsize / trans, host->hwcfg.sector_size_1k); - if (!ret) { + if (ret != -EBADMSG) { *err_addr = brcmnand_read_reg(ctrl, BRCMNAND_UNCORR_ADDR) | ((u64)(brcmnand_read_reg(ctrl, From 3cdfa312c66f7cad0a654f267ba89c587f45273a Mon Sep 17 00:00:00 2001 From: Mark Kettenis Date: Tue, 21 Dec 2021 17:31:50 +0100 Subject: [PATCH 09/13] armv8: apple: Disable PSCI reset Apple's ARMv8 cores don't implement EL3 and therefore don't provide a PSCI implementation. So don't attempt to use PSCI to reset on machines using Apple SoCs. Signed-off-by: Mark Kettenis --- arch/arm/cpu/armv8/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/cpu/armv8/Kconfig b/arch/arm/cpu/armv8/Kconfig index 0a3fdfa471..9967376eca 100644 --- a/arch/arm/cpu/armv8/Kconfig +++ b/arch/arm/cpu/armv8/Kconfig @@ -102,7 +102,7 @@ config PSCI_RESET bool "Use PSCI for reset and shutdown" default y select ARM_SMCCC if OF_CONTROL - depends on !ARCH_EXYNOS7 && !ARCH_BCM283X && \ + depends on !ARCH_APPLE && !ARCH_BCM283X && !ARCH_EXYNOS7 && \ !TARGET_LS2080AQDS && \ !TARGET_LS2080ARDB && !TARGET_LS2080A_EMU && \ !TARGET_LS1088ARDB && !TARGET_LS1088AQDS && \ From 703f8c8451bdd9918670e29fa42ead653db456fb Mon Sep 17 00:00:00 2001 From: Piotr Kubik Date: Wed, 29 Dec 2021 14:30:04 +0100 Subject: [PATCH 10/13] ARM: qemu-arm: Fix build fail with boot devices disabled BOOT_TARGET_DEVICES should only be added if the corresponding u-boot command is enabled otherwise the build will fail. Signed-off-by: Piotr Kubik --- include/configs/qemu-arm.h | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/include/configs/qemu-arm.h b/include/configs/qemu-arm.h index 1287fd1671..9fc53b4739 100644 --- a/include/configs/qemu-arm.h +++ b/include/configs/qemu-arm.h @@ -21,11 +21,35 @@ /* Environment options */ +#if CONFIG_IS_ENABLED(CMD_USB) +# define BOOT_TARGET_USB(func) func(USB, usb, 0) +#else +# define BOOT_TARGET_USB(func) +#endif + +#if CONFIG_IS_ENABLED(CMD_SCSI) +# define BOOT_TARGET_SCSI(func) func(SCSI, scsi, 0) +#else +# define BOOT_TARGET_SCSI(func) +#endif + +#if CONFIG_IS_ENABLED(CMD_VIRTIO) +# define BOOT_TARGET_VIRTIO(func) func(VIRTIO, virtio, 0) +#else +# define BOOT_TARGET_VIRTIO(func) +#endif + +#if CONFIG_IS_ENABLED(CMD_DHCP) +# define BOOT_TARGET_DHCP(func) func(DHCP, dhcp, na) +#else +# define BOOT_TARGET_DHCP(func) +#endif + #define BOOT_TARGET_DEVICES(func) \ - func(USB, usb, 0) \ - func(SCSI, scsi, 0) \ - func(VIRTIO, virtio, 0) \ - func(DHCP, dhcp, na) + BOOT_TARGET_USB(func) \ + BOOT_TARGET_SCSI(func) \ + BOOT_TARGET_VIRTIO(func) \ + BOOT_TARGET_DHCP(func) #include From 226fce6108fe364e35f3eb9a84ff1a7ec93727ce Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Thu, 30 Dec 2021 22:36:51 +0300 Subject: [PATCH 11/13] phy: Track power-on and init counts in uclass On boards using the RK3399 SoC, the USB OHCI and EHCI controllers share the same PHY device instance. While these controllers are being stopped they both attempt to power-off and deinitialize it, but trying to power-off the deinitialized PHY device results in a hang. This usually happens just before booting an OS, and can be explicitly triggered by running "usb start; usb stop" in the U-Boot shell. Implement a uclass-wide counting mechanism for PHY initialization and power state change requests, so that we don't power-off/deinitialize a PHY instance until all of its users want it done. The Allwinner A10 USB PHY driver does this counting in-driver, remove those parts in favour of this in-uclass implementation. The sandbox PHY operations test needs some changes since the uclass will no longer call into the drivers for actions matching its tracked state (e.g. powering-off a powered-off PHY). Update that test, and add a new one which simulates multiple users of a single PHY. The major complication here is that PHY handles aren't deduplicated per instance, so the obvious idea of putting the counts in the PHY handles don't immediately work. It seems possible to bind a child udevice per PHY instance to the PHY provider and deduplicate the handles in each child's uclass-private areas, like in the CLK framework. An alternative approach could be to use those bound child udevices themselves as the PHY handles. Instead, to avoid the architectural changes those would require, this patch solves things by dynamically allocating a list of structs (one per instance) in the provider's uclass-private area. Signed-off-by: Alper Nebi Yasak Reviewed-by: Simon Glass Tested-by: Peter Robinson - Rock960 --- drivers/phy/allwinner/phy-sun4i-usb.c | 9 -- drivers/phy/phy-uclass.c | 137 ++++++++++++++++++++++++++ test/dm/phy.c | 83 +++++++++++++++- 3 files changed, 215 insertions(+), 14 deletions(-) diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c index ab2a5d17fc..86c589a65f 100644 --- a/drivers/phy/allwinner/phy-sun4i-usb.c +++ b/drivers/phy/allwinner/phy-sun4i-usb.c @@ -125,7 +125,6 @@ struct sun4i_usb_phy_info { struct sun4i_usb_phy_plat { void __iomem *pmu; - int power_on_count; int gpio_vbus; int gpio_vbus_det; int gpio_id_det; @@ -225,10 +224,6 @@ static int sun4i_usb_phy_power_on(struct phy *phy) initial_usb_scan_delay = 0; } - usb_phy->power_on_count++; - if (usb_phy->power_on_count != 1) - return 0; - if (usb_phy->gpio_vbus >= 0) gpio_set_value(usb_phy->gpio_vbus, SUNXI_GPIO_PULL_UP); @@ -240,10 +235,6 @@ static int sun4i_usb_phy_power_off(struct phy *phy) struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev); struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id]; - usb_phy->power_on_count--; - if (usb_phy->power_on_count != 0) - return 0; - if (usb_phy->gpio_vbus >= 0) gpio_set_value(usb_phy->gpio_vbus, SUNXI_GPIO_PULL_DISABLE); diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c index 706e9fdf3a..49e2ec25c2 100644 --- a/drivers/phy/phy-uclass.c +++ b/drivers/phy/phy-uclass.c @@ -11,12 +11,96 @@ #include #include #include +#include + +/** + * struct phy_counts - Init and power-on counts of a single PHY port + * + * This structure is used to keep track of PHY initialization and power + * state change requests, so that we don't power off and deinitialize a + * PHY instance until all of its users want it done. Otherwise, multiple + * consumers using the same PHY port can cause problems (e.g. one might + * call power_off() after another's exit() and hang indefinitely). + * + * @id: The PHY ID within a PHY provider + * @power_on_count: Times generic_phy_power_on() was called for this ID + * without a matching generic_phy_power_off() afterwards + * @init_count: Times generic_phy_init() was called for this ID + * without a matching generic_phy_exit() afterwards + * @list: Handle for a linked list of these structures corresponding to + * ports of the same PHY provider + */ +struct phy_counts { + unsigned long id; + int power_on_count; + int init_count; + struct list_head list; +}; static inline struct phy_ops *phy_dev_ops(struct udevice *dev) { return (struct phy_ops *)dev->driver->ops; } +static struct phy_counts *phy_get_counts(struct phy *phy) +{ + struct list_head *uc_priv; + struct phy_counts *counts; + + if (!generic_phy_valid(phy)) + return NULL; + + uc_priv = dev_get_uclass_priv(phy->dev); + list_for_each_entry(counts, uc_priv, list) + if (counts->id == phy->id) + return counts; + + return NULL; +} + +static int phy_alloc_counts(struct phy *phy) +{ + struct list_head *uc_priv; + struct phy_counts *counts; + + if (!generic_phy_valid(phy)) + return 0; + if (phy_get_counts(phy)) + return 0; + + uc_priv = dev_get_uclass_priv(phy->dev); + counts = kzalloc(sizeof(*counts), GFP_KERNEL); + if (!counts) + return -ENOMEM; + + counts->id = phy->id; + counts->power_on_count = 0; + counts->init_count = 0; + list_add(&counts->list, uc_priv); + + return 0; +} + +static int phy_uclass_pre_probe(struct udevice *dev) +{ + struct list_head *uc_priv = dev_get_uclass_priv(dev); + + INIT_LIST_HEAD(uc_priv); + + return 0; +} + +static int phy_uclass_pre_remove(struct udevice *dev) +{ + struct list_head *uc_priv = dev_get_uclass_priv(dev); + struct phy_counts *counts, *next; + + list_for_each_entry_safe(counts, next, uc_priv, list) + kfree(counts); + + return 0; +} + static int generic_phy_xlate_offs_flags(struct phy *phy, struct ofnode_phandle_args *args) { @@ -88,6 +172,12 @@ int generic_phy_get_by_index_nodev(ofnode node, int index, struct phy *phy) goto err; } + ret = phy_alloc_counts(phy); + if (ret) { + debug("phy_alloc_counts() failed: %d\n", ret); + goto err; + } + return 0; err: @@ -118,6 +208,7 @@ int generic_phy_get_by_name(struct udevice *dev, const char *phy_name, int generic_phy_init(struct phy *phy) { + struct phy_counts *counts; struct phy_ops const *ops; int ret; @@ -126,10 +217,19 @@ int generic_phy_init(struct phy *phy) ops = phy_dev_ops(phy->dev); if (!ops->init) return 0; + + counts = phy_get_counts(phy); + if (counts->init_count > 0) { + counts->init_count++; + return 0; + } + ret = ops->init(phy); if (ret) dev_err(phy->dev, "PHY: Failed to init %s: %d.\n", phy->dev->name, ret); + else + counts->init_count = 1; return ret; } @@ -154,6 +254,7 @@ int generic_phy_reset(struct phy *phy) int generic_phy_exit(struct phy *phy) { + struct phy_counts *counts; struct phy_ops const *ops; int ret; @@ -162,16 +263,28 @@ int generic_phy_exit(struct phy *phy) ops = phy_dev_ops(phy->dev); if (!ops->exit) return 0; + + counts = phy_get_counts(phy); + if (counts->init_count == 0) + return 0; + if (counts->init_count > 1) { + counts->init_count--; + return 0; + } + ret = ops->exit(phy); if (ret) dev_err(phy->dev, "PHY: Failed to exit %s: %d.\n", phy->dev->name, ret); + else + counts->init_count = 0; return ret; } int generic_phy_power_on(struct phy *phy) { + struct phy_counts *counts; struct phy_ops const *ops; int ret; @@ -180,16 +293,26 @@ int generic_phy_power_on(struct phy *phy) ops = phy_dev_ops(phy->dev); if (!ops->power_on) return 0; + + counts = phy_get_counts(phy); + if (counts->power_on_count > 0) { + counts->power_on_count++; + return 0; + } + ret = ops->power_on(phy); if (ret) dev_err(phy->dev, "PHY: Failed to power on %s: %d.\n", phy->dev->name, ret); + else + counts->power_on_count = 1; return ret; } int generic_phy_power_off(struct phy *phy) { + struct phy_counts *counts; struct phy_ops const *ops; int ret; @@ -198,10 +321,21 @@ int generic_phy_power_off(struct phy *phy) ops = phy_dev_ops(phy->dev); if (!ops->power_off) return 0; + + counts = phy_get_counts(phy); + if (counts->power_on_count == 0) + return 0; + if (counts->power_on_count > 1) { + counts->power_on_count--; + return 0; + } + ret = ops->power_off(phy); if (ret) dev_err(phy->dev, "PHY: Failed to power off %s: %d.\n", phy->dev->name, ret); + else + counts->power_on_count = 0; return ret; } @@ -316,4 +450,7 @@ int generic_phy_power_off_bulk(struct phy_bulk *bulk) UCLASS_DRIVER(phy) = { .id = UCLASS_PHY, .name = "phy", + .pre_probe = phy_uclass_pre_probe, + .pre_remove = phy_uclass_pre_remove, + .per_device_auto = sizeof(struct list_head), }; diff --git a/test/dm/phy.c b/test/dm/phy.c index ecbd47bf12..df4c73fc70 100644 --- a/test/dm/phy.c +++ b/test/dm/phy.c @@ -79,12 +79,15 @@ static int dm_test_phy_ops(struct unit_test_state *uts) ut_assertok(generic_phy_power_off(&phy1)); /* - * test operations after exit(). - * The sandbox phy driver does not allow it. + * Test power_on() failure after exit(). + * The sandbox phy driver does not allow power-on/off after + * exit, but the uclass counts power-on/init calls and skips + * calling the driver's ops when e.g. powering off an already + * powered-off phy. */ ut_assertok(generic_phy_exit(&phy1)); ut_assert(generic_phy_power_on(&phy1) != 0); - ut_assert(generic_phy_power_off(&phy1) != 0); + ut_assertok(generic_phy_power_off(&phy1)); /* * test normal operations again (after re-init) @@ -99,6 +102,17 @@ static int dm_test_phy_ops(struct unit_test_state *uts) */ ut_assertok(generic_phy_reset(&phy1)); + /* + * Test power_off() failure after exit(). + * For this we need to call exit() while the phy is powered-on, + * so that the uclass actually calls the driver's power-off() + * and reports the resulting failure. + */ + ut_assertok(generic_phy_power_on(&phy1)); + ut_assertok(generic_phy_exit(&phy1)); + ut_assert(generic_phy_power_off(&phy1) != 0); + ut_assertok(generic_phy_power_on(&phy1)); + /* PHY2 has a known problem with power off */ ut_assertok(generic_phy_init(&phy2)); ut_assertok(generic_phy_power_on(&phy2)); @@ -106,8 +120,8 @@ static int dm_test_phy_ops(struct unit_test_state *uts) /* PHY3 has a known problem with power off and power on */ ut_assertok(generic_phy_init(&phy3)); - ut_asserteq(-EIO, generic_phy_power_off(&phy3)); - ut_asserteq(-EIO, generic_phy_power_off(&phy3)); + ut_asserteq(-EIO, generic_phy_power_on(&phy3)); + ut_assertok(generic_phy_power_off(&phy3)); return 0; } @@ -145,3 +159,62 @@ static int dm_test_phy_bulk(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_phy_bulk, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +static int dm_test_phy_multi_exit(struct unit_test_state *uts) +{ + struct phy phy1_method1; + struct phy phy1_method2; + struct phy phy1_method3; + struct udevice *parent; + + /* Get the same phy instance in 3 different ways. */ + ut_assertok(uclass_get_device_by_name(UCLASS_SIMPLE_BUS, + "gen_phy_user", &parent)); + ut_assertok(generic_phy_get_by_name(parent, "phy1", &phy1_method1)); + ut_asserteq(0, phy1_method1.id); + ut_assertok(generic_phy_get_by_name(parent, "phy1", &phy1_method2)); + ut_asserteq(0, phy1_method2.id); + ut_asserteq_ptr(phy1_method1.dev, phy1_method1.dev); + + ut_assertok(uclass_get_device_by_name(UCLASS_SIMPLE_BUS, + "gen_phy_user1", &parent)); + ut_assertok(generic_phy_get_by_name(parent, "phy1", &phy1_method3)); + ut_asserteq(0, phy1_method3.id); + ut_asserteq_ptr(phy1_method1.dev, phy1_method3.dev); + + /* + * Test using the same PHY from different handles. + * In non-test code these could be in different drivers. + */ + + /* + * These must only call the driver's ops at the first init() + * and power_on(). + */ + ut_assertok(generic_phy_init(&phy1_method1)); + ut_assertok(generic_phy_init(&phy1_method2)); + ut_assertok(generic_phy_power_on(&phy1_method1)); + ut_assertok(generic_phy_power_on(&phy1_method2)); + ut_assertok(generic_phy_init(&phy1_method3)); + ut_assertok(generic_phy_power_on(&phy1_method3)); + + /* + * These must not call the driver's ops as other handles still + * want the PHY powered-on and initialized. + */ + ut_assertok(generic_phy_power_off(&phy1_method3)); + ut_assertok(generic_phy_exit(&phy1_method3)); + + /* + * We would get an error here if the generic_phy_exit() above + * actually called the driver's exit(), as the sandbox driver + * doesn't allow power-off() after exit(). + */ + ut_assertok(generic_phy_power_off(&phy1_method1)); + ut_assertok(generic_phy_power_off(&phy1_method2)); + ut_assertok(generic_phy_exit(&phy1_method1)); + ut_assertok(generic_phy_exit(&phy1_method2)); + + return 0; +} +DM_TEST(dm_test_phy_multi_exit, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); From f6f27be146b6313cf4b1cee99a671d3097419ca8 Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Sun, 2 Jan 2022 11:38:35 +0000 Subject: [PATCH 12/13] env: fat: Add new lines at the end of print statements Add some new line feeds at the end of print messages to make things easier to read on the console. The other env options do this so this is just an omission for FAT env. Signed-off-by: Peter Robinson --- env/fat.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/env/fat.c b/env/fat.c index 9d37d26f9e..fdccd6cd2a 100644 --- a/env/fat.c +++ b/env/fat.c @@ -77,7 +77,7 @@ static int env_fat_save(void) * This printf is embedded in the messages from env_save that * will calling it. The missing \n is intentional. */ - printf("Unable to use %s %d:%d... ", + printf("Unable to use %s %d:%d... \n", CONFIG_ENV_FAT_INTERFACE, dev, part); return 1; } @@ -93,7 +93,7 @@ static int env_fat_save(void) * This printf is embedded in the messages from env_save that * will calling it. The missing \n is intentional. */ - printf("Unable to write \"%s\" from %s%d:%d... ", + printf("Unable to write \"%s\" from %s%d:%d... \n", file, CONFIG_ENV_FAT_INTERFACE, dev, part); return 1; } @@ -135,7 +135,7 @@ static int env_fat_load(void) * This printf is embedded in the messages from env_save that * will calling it. The missing \n is intentional. */ - printf("Unable to use %s %d:%d... ", + printf("Unable to use %s %d:%d... \n", CONFIG_ENV_FAT_INTERFACE, dev, part); goto err_env_relocate; } @@ -153,7 +153,7 @@ static int env_fat_load(void) * This printf is embedded in the messages from env_save that * will calling it. The missing \n is intentional. */ - printf("Unable to read \"%s\" from %s%d:%d... ", + printf("Unable to read \"%s\" from %s%d:%d... \n", CONFIG_ENV_FAT_FILE, CONFIG_ENV_FAT_INTERFACE, dev, part); goto err_env_relocate; } From 97f2a749d5126b2908dd282969c02c3632417c68 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Tue, 4 Jan 2022 18:20:19 +0200 Subject: [PATCH 13/13] lib: Kconfig: fix PHANDLE_CHECK_SEQ position outside of menu CONFIG_PHANDLE_CHECK_SEQ is outside of the menu 'Library routines' thus it's invisible in menuconfig and cannot be selected. Fix this by moving the 'endmenu' after the PHANDLE_CHECK_SEQ definition Fixes: c589132a1d ("fdt: Use phandle to distinguish DT nodes with same name") Signed-off-by: Eugen Hristev Reviewed-by: Aswath Govindraju Reviewed-by: Simon Glass --- lib/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Kconfig b/lib/Kconfig index 1883ac734d..35fc9e418c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -837,11 +837,11 @@ config LMB_RESERVED_REGIONS Define the number of supported reserved regions in the library logical memory blocks. -endmenu - config PHANDLE_CHECK_SEQ bool "Enable phandle check while getting sequence number" help When there are multiple device tree nodes with same name, enable this config option to distinguish them using phandles in fdtdec_get_alias_seq() function. + +endmenu