--- /dev/null
+From 260364d112bc822005224667c0c9b1b17a53eafd Mon Sep 17 00:00:00 2001
+From: Mike Rapoport <rppt@linux.ibm.com>
+Date: Mon, 9 May 2022 17:34:28 -0700
+Subject: arm[64]/memremap: don't abuse pfn_valid() to ensure presence of linear map
+
+From: Mike Rapoport <rppt@linux.ibm.com>
+
+commit 260364d112bc822005224667c0c9b1b17a53eafd upstream.
+
+The semantics of pfn_valid() is to check presence of the memory map for a
+PFN and not whether a PFN is covered by the linear map. The memory map
+may be present for NOMAP memory regions, but they won't be mapped in the
+linear mapping. Accessing such regions via __va() when they are
+memremap()'ed will cause a crash.
+
+On v5.4.y the crash happens on qemu-arm with UEFI [1]:
+
+<1>[ 0.084476] 8<--- cut here ---
+<1>[ 0.084595] Unable to handle kernel paging request at virtual address dfb76000
+<1>[ 0.084938] pgd = (ptrval)
+<1>[ 0.085038] [dfb76000] *pgd=5f7fe801, *pte=00000000, *ppte=00000000
+
+...
+
+<4>[ 0.093923] [<c0ed6ce8>] (memcpy) from [<c16a06f8>] (dmi_setup+0x60/0x418)
+<4>[ 0.094204] [<c16a06f8>] (dmi_setup) from [<c16a38d4>] (arm_dmi_init+0x8/0x10)
+<4>[ 0.094408] [<c16a38d4>] (arm_dmi_init) from [<c0302e9c>] (do_one_initcall+0x50/0x228)
+<4>[ 0.094619] [<c0302e9c>] (do_one_initcall) from [<c16011e4>] (kernel_init_freeable+0x15c/0x1f8)
+<4>[ 0.094841] [<c16011e4>] (kernel_init_freeable) from [<c0f028cc>] (kernel_init+0x8/0x10c)
+<4>[ 0.095057] [<c0f028cc>] (kernel_init) from [<c03010e8>] (ret_from_fork+0x14/0x2c)
+
+On kernels v5.10.y and newer the same crash won't reproduce on ARM because
+commit b10d6bca8720 ("arch, drivers: replace for_each_membock() with
+for_each_mem_range()") changed the way memory regions are registered in
+the resource tree, but that merely covers up the problem.
+
+On ARM64 memory resources registered in yet another way and there the
+issue of wrong usage of pfn_valid() to ensure availability of the linear
+map is also covered.
+
+Implement arch_memremap_can_ram_remap() on ARM and ARM64 to prevent access
+to NOMAP regions via the linear mapping in memremap().
+
+Link: https://lore.kernel.org/all/Yl65zxGgFzF1Okac@sirena.org.uk
+Link: https://lkml.kernel.org/r/20220426060107.7618-1-rppt@kernel.org
+Signed-off-by: Mike Rapoport <rppt@linux.ibm.com>
+Reported-by: "kernelci.org bot" <bot@kernelci.org>
+Tested-by: Mark Brown <broonie@kernel.org>
+Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
+Acked-by: Catalin Marinas <catalin.marinas@arm.com>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: Mark Brown <broonie@kernel.org>
+Cc: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
+Cc: Russell King <linux@armlinux.org.uk>
+Cc: Tony Lindgren <tony@atomide.com>
+Cc: Will Deacon <will@kernel.org>
+Cc: <stable@vger.kernel.org> [5.4+]
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Mike Rapoport <rppt@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm/include/asm/io.h | 3 +++
+ arch/arm/mm/ioremap.c | 8 ++++++++
+ arch/arm64/include/asm/io.h | 4 ++++
+ arch/arm64/mm/ioremap.c | 9 +++++++++
+ 4 files changed, 24 insertions(+)
+
+--- a/arch/arm/include/asm/io.h
++++ b/arch/arm/include/asm/io.h
+@@ -457,6 +457,9 @@ extern void pci_iounmap(struct pci_dev *
+ extern int valid_phys_addr_range(phys_addr_t addr, size_t size);
+ extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size);
+ extern int devmem_is_allowed(unsigned long pfn);
++extern bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size,
++ unsigned long flags);
++#define arch_memremap_can_ram_remap arch_memremap_can_ram_remap
+ #endif
+
+ /*
+--- a/arch/arm/mm/ioremap.c
++++ b/arch/arm/mm/ioremap.c
+@@ -500,3 +500,11 @@ void __init early_ioremap_init(void)
+ {
+ early_ioremap_setup();
+ }
++
++bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size,
++ unsigned long flags)
++{
++ unsigned long pfn = PHYS_PFN(offset);
++
++ return memblock_is_map_memory(pfn);
++}
+--- a/arch/arm64/include/asm/io.h
++++ b/arch/arm64/include/asm/io.h
+@@ -204,4 +204,8 @@ extern int valid_mmap_phys_addr_range(un
+
+ extern int devmem_is_allowed(unsigned long pfn);
+
++extern bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size,
++ unsigned long flags);
++#define arch_memremap_can_ram_remap arch_memremap_can_ram_remap
++
+ #endif /* __ASM_IO_H */
+--- a/arch/arm64/mm/ioremap.c
++++ b/arch/arm64/mm/ioremap.c
+@@ -13,6 +13,7 @@
+ #include <linux/mm.h>
+ #include <linux/vmalloc.h>
+ #include <linux/io.h>
++#include <linux/memblock.h>
+
+ #include <asm/fixmap.h>
+ #include <asm/tlbflush.h>
+@@ -100,3 +101,11 @@ void __init early_ioremap_init(void)
+ {
+ early_ioremap_setup();
+ }
++
++bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size,
++ unsigned long flags)
++{
++ unsigned long pfn = PHYS_PFN(offset);
++
++ return memblock_is_map_memory(pfn);
++}
--- /dev/null
+From 91a7cda1f4b8bdf770000a3b60640576dafe0cec Mon Sep 17 00:00:00 2001
+From: Francesco Dolcini <francesco.dolcini@toradex.com>
+Date: Fri, 6 May 2022 08:08:15 +0200
+Subject: net: phy: Fix race condition on link status change
+
+From: Francesco Dolcini <francesco.dolcini@toradex.com>
+
+commit 91a7cda1f4b8bdf770000a3b60640576dafe0cec upstream.
+
+This fixes the following error caused by a race condition between
+phydev->adjust_link() and a MDIO transaction in the phy interrupt
+handler. The issue was reproduced with the ethernet FEC driver and a
+micrel KSZ9031 phy.
+
+[ 146.195696] fec 2188000.ethernet eth0: MDIO read timeout
+[ 146.201779] ------------[ cut here ]------------
+[ 146.206671] WARNING: CPU: 0 PID: 571 at drivers/net/phy/phy.c:942 phy_error+0x24/0x6c
+[ 146.214744] Modules linked in: bnep imx_vdoa imx_sdma evbug
+[ 146.220640] CPU: 0 PID: 571 Comm: irq/128-2188000 Not tainted 5.18.0-rc3-00080-gd569e86915b7 #9
+[ 146.229563] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
+[ 146.236257] unwind_backtrace from show_stack+0x10/0x14
+[ 146.241640] show_stack from dump_stack_lvl+0x58/0x70
+[ 146.246841] dump_stack_lvl from __warn+0xb4/0x24c
+[ 146.251772] __warn from warn_slowpath_fmt+0x5c/0xd4
+[ 146.256873] warn_slowpath_fmt from phy_error+0x24/0x6c
+[ 146.262249] phy_error from kszphy_handle_interrupt+0x40/0x48
+[ 146.268159] kszphy_handle_interrupt from irq_thread_fn+0x1c/0x78
+[ 146.274417] irq_thread_fn from irq_thread+0xf0/0x1dc
+[ 146.279605] irq_thread from kthread+0xe4/0x104
+[ 146.284267] kthread from ret_from_fork+0x14/0x28
+[ 146.289164] Exception stack(0xe6fa1fb0 to 0xe6fa1ff8)
+[ 146.294448] 1fa0: 00000000 00000000 00000000 00000000
+[ 146.302842] 1fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
+[ 146.311281] 1fe0: 00000000 00000000 00000000 00000000 00000013 00000000
+[ 146.318262] irq event stamp: 12325
+[ 146.321780] hardirqs last enabled at (12333): [<c01984c4>] __up_console_sem+0x50/0x60
+[ 146.330013] hardirqs last disabled at (12342): [<c01984b0>] __up_console_sem+0x3c/0x60
+[ 146.338259] softirqs last enabled at (12324): [<c01017f0>] __do_softirq+0x2c0/0x624
+[ 146.346311] softirqs last disabled at (12319): [<c01300ac>] __irq_exit_rcu+0x138/0x178
+[ 146.354447] ---[ end trace 0000000000000000 ]---
+
+With the FEC driver phydev->adjust_link() calls fec_enet_adjust_link()
+calls fec_stop()/fec_restart() and both these function reset and
+temporary disable the FEC disrupting any MII transaction that
+could be happening at the same time.
+
+fec_enet_adjust_link() and phy_read() can be running at the same time
+when we have one additional interrupt before the phy_state_machine() is
+able to terminate.
+
+Thread 1 (phylib WQ) | Thread 2 (phy interrupt)
+ |
+ | phy_interrupt() <-- PHY IRQ
+ | handle_interrupt()
+ | phy_read()
+ | phy_trigger_machine()
+ | --> schedule phylib WQ
+ |
+ |
+phy_state_machine() |
+ phy_check_link_status() |
+ phy_link_change() |
+ phydev->adjust_link() |
+ fec_enet_adjust_link() |
+ --> FEC reset | phy_interrupt() <-- PHY IRQ
+ | phy_read()
+ |
+
+Fix this by acquiring the phydev lock in phy_interrupt().
+
+Link: https://lore.kernel.org/all/20220422152612.GA510015@francesco-nb.int.toradex.com/
+Fixes: c974bdbc3e77 ("net: phy: Use threaded IRQ, to allow IRQ from sleeping devices")
+cc: <stable@vger.kernel.org>
+Signed-off-by: Francesco Dolcini <francesco.dolcini@toradex.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://lore.kernel.org/r/20220506060815.327382-1-francesco.dolcini@toradex.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[fd: backport: adapt locking before did_interrupt()/ack_interrupt()
+ callbacks removal ]
+Signed-off-by: Francesco Dolcini <francesco.dolcini@toradex.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/phy/phy.c | 45 ++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 40 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -116,10 +116,15 @@ EXPORT_SYMBOL(phy_print_status);
+ */
+ static int phy_clear_interrupt(struct phy_device *phydev)
+ {
+- if (phydev->drv->ack_interrupt)
+- return phydev->drv->ack_interrupt(phydev);
++ int ret = 0;
+
+- return 0;
++ if (phydev->drv->ack_interrupt) {
++ mutex_lock(&phydev->lock);
++ ret = phydev->drv->ack_interrupt(phydev);
++ mutex_unlock(&phydev->lock);
++ }
++
++ return ret;
+ }
+
+ /**
+@@ -761,6 +766,36 @@ static int phy_disable_interrupts(struct
+ }
+
+ /**
++ * phy_did_interrupt - Checks if the PHY generated an interrupt
++ * @phydev: target phy_device struct
++ */
++static int phy_did_interrupt(struct phy_device *phydev)
++{
++ int ret;
++
++ mutex_lock(&phydev->lock);
++ ret = phydev->drv->did_interrupt(phydev);
++ mutex_unlock(&phydev->lock);
++
++ return ret;
++}
++
++/**
++ * phy_handle_interrupt - PHY specific interrupt handler
++ * @phydev: target phy_device struct
++ */
++static int phy_handle_interrupt(struct phy_device *phydev)
++{
++ int ret;
++
++ mutex_lock(&phydev->lock);
++ ret = phydev->drv->handle_interrupt(phydev);
++ mutex_unlock(&phydev->lock);
++
++ return ret;
++}
++
++/**
+ * phy_interrupt - PHY interrupt handler
+ * @irq: interrupt line
+ * @phy_dat: phy_device pointer
+@@ -771,11 +806,11 @@ static irqreturn_t phy_interrupt(int irq
+ {
+ struct phy_device *phydev = phy_dat;
+
+- if (phydev->drv->did_interrupt && !phydev->drv->did_interrupt(phydev))
++ if (phydev->drv->did_interrupt && !phy_did_interrupt(phydev))
+ return IRQ_NONE;
+
+ if (phydev->drv->handle_interrupt) {
+- if (phydev->drv->handle_interrupt(phydev))
++ if (phy_handle_interrupt(phydev))
+ goto phy_err;
+ } else {
+ /* reschedule state queue work to run as soon as possible */