commit:     ffcf9f68f9a2e99641b96e1629e477e770e99f48
Author:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
AuthorDate: Sun Nov 21 20:42:40 2021 +0000
Commit:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
CommitDate: Sun Nov 21 20:42:40 2021 +0000
URL:        https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=ffcf9f68

Linux patch 5.10.81

Signed-off-by: Mike Pagano <mpagano <AT> gentoo.org>

 0000_README              |    4 +
 1080_linux-5.10.81.patch | 1173 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1177 insertions(+)

diff --git a/0000_README b/0000_README
index 22873d23..f4fa5656 100644
--- a/0000_README
+++ b/0000_README
@@ -363,6 +363,10 @@ Patch:  1079_linux-5.10.80.patch
 From:   http://www.kernel.org
 Desc:   Linux 5.10.80
 
+Patch:  1080_linux-5.10.81.patch
+From:   http://www.kernel.org
+Desc:   Linux 5.10.81
+
 Patch:  1500_XATTR_USER_PREFIX.patch
 From:   https://bugs.gentoo.org/show_bug.cgi?id=470644
 Desc:   Support for namespace user.pax.* on tmpfs.

diff --git a/1080_linux-5.10.81.patch b/1080_linux-5.10.81.patch
new file mode 100644
index 00000000..0a03b38e
--- /dev/null
+++ b/1080_linux-5.10.81.patch
@@ -0,0 +1,1173 @@
+diff --git a/Makefile b/Makefile
+index 71fdc74801e0a..1baeadb574f1c 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ VERSION = 5
+ PATCHLEVEL = 10
+-SUBLEVEL = 80
++SUBLEVEL = 81
+ EXTRAVERSION =
+ NAME = Dare mighty things
+ 
+diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
+index 9c76d50a5654b..3da39140babcf 100644
+--- a/arch/parisc/kernel/entry.S
++++ b/arch/parisc/kernel/entry.S
+@@ -1849,7 +1849,7 @@ syscall_restore:
+ 
+       /* Are we being ptraced? */
+       LDREG   TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19
+-      ldi     _TIF_SYSCALL_TRACE_MASK,%r2
++      ldi     _TIF_SINGLESTEP|_TIF_BLOCKSTEP,%r2
+       and,COND(=)     %r19,%r2,%r0
+       b,n     syscall_restore_rfi
+ 
+diff --git a/arch/x86/include/asm/insn-eval.h 
b/arch/x86/include/asm/insn-eval.h
+index 98b4dae5e8bc8..c1438f9239e46 100644
+--- a/arch/x86/include/asm/insn-eval.h
++++ b/arch/x86/include/asm/insn-eval.h
+@@ -21,6 +21,7 @@ int insn_get_modrm_rm_off(struct insn *insn, struct pt_regs 
*regs);
+ int insn_get_modrm_reg_off(struct insn *insn, struct pt_regs *regs);
+ unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx);
+ int insn_get_code_seg_params(struct pt_regs *regs);
++unsigned long insn_get_effective_ip(struct pt_regs *regs);
+ int insn_fetch_from_user(struct pt_regs *regs,
+                        unsigned char buf[MAX_INSN_SIZE]);
+ int insn_fetch_from_user_inatomic(struct pt_regs *regs,
+diff --git a/arch/x86/include/asm/processor.h 
b/arch/x86/include/asm/processor.h
+index 50d02db723177..d428d611a43a9 100644
+--- a/arch/x86/include/asm/processor.h
++++ b/arch/x86/include/asm/processor.h
+@@ -534,6 +534,7 @@ struct thread_struct {
+        */
+       unsigned long           iopl_emul;
+ 
++      unsigned int            iopl_warn:1;
+       unsigned int            sig_on_uaccess_err:1;
+ 
+       /* Floating point and extended processor state */
+diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
+index 145a7ac0c19aa..0aa1baf9a3afc 100644
+--- a/arch/x86/kernel/process.c
++++ b/arch/x86/kernel/process.c
+@@ -138,6 +138,7 @@ int copy_thread(unsigned long clone_flags, unsigned long 
sp, unsigned long arg,
+       frame->ret_addr = (unsigned long) ret_from_fork;
+       p->thread.sp = (unsigned long) fork_frame;
+       p->thread.io_bitmap = NULL;
++      p->thread.iopl_warn = 0;
+       memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
+ 
+ #ifdef CONFIG_X86_64
+diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
+index 143fcb8af38f4..2d4ecd50e69b8 100644
+--- a/arch/x86/kernel/traps.c
++++ b/arch/x86/kernel/traps.c
+@@ -523,6 +523,37 @@ static enum kernel_gp_hint get_kernel_gp_address(struct 
pt_regs *regs,
+ 
+ #define GPFSTR "general protection fault"
+ 
++static bool fixup_iopl_exception(struct pt_regs *regs)
++{
++      struct thread_struct *t = &current->thread;
++      unsigned char byte;
++      unsigned long ip;
++
++      if (!IS_ENABLED(CONFIG_X86_IOPL_IOPERM) || t->iopl_emul != 3)
++              return false;
++
++      ip = insn_get_effective_ip(regs);
++      if (!ip)
++              return false;
++
++      if (get_user(byte, (const char __user *)ip))
++              return false;
++
++      if (byte != 0xfa && byte != 0xfb)
++              return false;
++
++      if (!t->iopl_warn && printk_ratelimit()) {
++              pr_err("%s[%d] attempts to use CLI/STI, pretending it's a NOP, 
ip:%lx",
++                     current->comm, task_pid_nr(current), ip);
++              print_vma_addr(KERN_CONT " in ", ip);
++              pr_cont("\n");
++              t->iopl_warn = 1;
++      }
++
++      regs->ip += 1;
++      return true;
++}
++
+ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection)
+ {
+       char desc[sizeof(GPFSTR) + 50 + 2*sizeof(unsigned long) + 1] = GPFSTR;
+@@ -548,6 +579,9 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection)
+       tsk = current;
+ 
+       if (user_mode(regs)) {
++              if (fixup_iopl_exception(regs))
++                      goto exit;
++
+               tsk->thread.error_code = error_code;
+               tsk->thread.trap_nr = X86_TRAP_GP;
+ 
+diff --git a/arch/x86/lib/insn-eval.c b/arch/x86/lib/insn-eval.c
+index bb0b3fe1e0a02..c6a19c88af547 100644
+--- a/arch/x86/lib/insn-eval.c
++++ b/arch/x86/lib/insn-eval.c
+@@ -1415,7 +1415,7 @@ void __user *insn_get_addr_ref(struct insn *insn, struct 
pt_regs *regs)
+       }
+ }
+ 
+-static unsigned long insn_get_effective_ip(struct pt_regs *regs)
++unsigned long insn_get_effective_ip(struct pt_regs *regs)
+ {
+       unsigned long seg_base = 0;
+ 
+diff --git a/drivers/block/loop.c b/drivers/block/loop.c
+index f0fa0c8e7ec60..ee537a9f1d1a4 100644
+--- a/drivers/block/loop.c
++++ b/drivers/block/loop.c
+@@ -228,19 +228,6 @@ static void __loop_update_dio(struct loop_device *lo, 
bool dio)
+               blk_mq_unfreeze_queue(lo->lo_queue);
+ }
+ 
+-/**
+- * loop_validate_block_size() - validates the passed in block size
+- * @bsize: size to validate
+- */
+-static int
+-loop_validate_block_size(unsigned short bsize)
+-{
+-      if (bsize < 512 || bsize > PAGE_SIZE || !is_power_of_2(bsize))
+-              return -EINVAL;
+-
+-      return 0;
+-}
+-
+ /**
+  * loop_set_size() - sets device size and notifies userspace
+  * @lo: struct loop_device to set the size for
+@@ -1121,7 +1108,7 @@ static int loop_configure(struct loop_device *lo, 
fmode_t mode,
+       }
+ 
+       if (config->block_size) {
+-              error = loop_validate_block_size(config->block_size);
++              error = blk_validate_block_size(config->block_size);
+               if (error)
+                       goto out_unlock;
+       }
+@@ -1617,7 +1604,7 @@ static int loop_set_block_size(struct loop_device *lo, 
unsigned long arg)
+       if (lo->lo_state != Lo_bound)
+               return -ENXIO;
+ 
+-      err = loop_validate_block_size(arg);
++      err = blk_validate_block_size(arg);
+       if (err)
+               return err;
+ 
+diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c 
b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+index 6ef30252bfe0a..143b2cb13bf94 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+@@ -21,7 +21,6 @@
+ #include <linux/delay.h>
+ #include <linux/mfd/syscon.h>
+ #include <linux/regmap.h>
+-#include <linux/pm_runtime.h>
+ 
+ #include "stmmac_platform.h"
+ 
+@@ -1336,9 +1335,6 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
+               return ret;
+       }
+ 
+-      pm_runtime_enable(dev);
+-      pm_runtime_get_sync(dev);
+-
+       if (bsp_priv->integrated_phy)
+               rk_gmac_integrated_phy_powerup(bsp_priv);
+ 
+@@ -1347,14 +1343,9 @@ static int rk_gmac_powerup(struct rk_priv_data 
*bsp_priv)
+ 
+ static void rk_gmac_powerdown(struct rk_priv_data *gmac)
+ {
+-      struct device *dev = &gmac->pdev->dev;
+-
+       if (gmac->integrated_phy)
+               rk_gmac_integrated_phy_powerdown(gmac);
+ 
+-      pm_runtime_put_sync(dev);
+-      pm_runtime_disable(dev);
+-
+       phy_power_on(gmac, false);
+       gmac_clk_enable(gmac, false);
+ }
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h 
b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+index 727e68dfaf1c2..a4ca283e02284 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+@@ -270,6 +270,7 @@ void stmmac_disable_eee_mode(struct stmmac_priv *priv);
+ bool stmmac_eee_init(struct stmmac_priv *priv);
+ int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt);
+ int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size);
++int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled);
+ 
+ #if IS_ENABLED(CONFIG_STMMAC_SELFTESTS)
+ void stmmac_selftest_run(struct net_device *dev,
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index 0ac61e7ab43cd..4a75e73f06bbd 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -28,6 +28,7 @@
+ #include <linux/if_vlan.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/slab.h>
++#include <linux/pm_runtime.h>
+ #include <linux/prefetch.h>
+ #include <linux/pinctrl/consumer.h>
+ #ifdef CONFIG_DEBUG_FS
+@@ -113,6 +114,28 @@ static void stmmac_exit_fs(struct net_device *dev);
+ 
+ #define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
+ 
++int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled)
++{
++      int ret = 0;
++
++      if (enabled) {
++              ret = clk_prepare_enable(priv->plat->stmmac_clk);
++              if (ret)
++                      return ret;
++              ret = clk_prepare_enable(priv->plat->pclk);
++              if (ret) {
++                      clk_disable_unprepare(priv->plat->stmmac_clk);
++                      return ret;
++              }
++      } else {
++              clk_disable_unprepare(priv->plat->stmmac_clk);
++              clk_disable_unprepare(priv->plat->pclk);
++      }
++
++      return ret;
++}
++EXPORT_SYMBOL_GPL(stmmac_bus_clks_config);
++
+ /**
+  * stmmac_verify_args - verify the driver parameters.
+  * Description: it checks the driver parameters and set a default in case of
+@@ -2792,6 +2815,12 @@ static int stmmac_open(struct net_device *dev)
+       u32 chan;
+       int ret;
+ 
++      ret = pm_runtime_get_sync(priv->device);
++      if (ret < 0) {
++              pm_runtime_put_noidle(priv->device);
++              return ret;
++      }
++
+       if (priv->hw->pcs != STMMAC_PCS_TBI &&
+           priv->hw->pcs != STMMAC_PCS_RTBI &&
+           priv->hw->xpcs == NULL) {
+@@ -2800,7 +2829,7 @@ static int stmmac_open(struct net_device *dev)
+                       netdev_err(priv->dev,
+                                  "%s: Cannot attach to PHY (error: %d)\n",
+                                  __func__, ret);
+-                      return ret;
++                      goto init_phy_error;
+               }
+       }
+ 
+@@ -2915,6 +2944,8 @@ init_error:
+       free_dma_desc_resources(priv);
+ dma_desc_error:
+       phylink_disconnect_phy(priv->phylink);
++init_phy_error:
++      pm_runtime_put(priv->device);
+       return ret;
+ }
+ 
+@@ -2965,6 +2996,8 @@ static int stmmac_release(struct net_device *dev)
+ 
+       stmmac_release_ptp(priv);
+ 
++      pm_runtime_put(priv->device);
++
+       return 0;
+ }
+ 
+@@ -4291,12 +4324,21 @@ static int stmmac_set_mac_address(struct net_device 
*ndev, void *addr)
+       struct stmmac_priv *priv = netdev_priv(ndev);
+       int ret = 0;
+ 
++      ret = pm_runtime_get_sync(priv->device);
++      if (ret < 0) {
++              pm_runtime_put_noidle(priv->device);
++              return ret;
++      }
++
+       ret = eth_mac_addr(ndev, addr);
+       if (ret)
+-              return ret;
++              goto set_mac_error;
+ 
+       stmmac_set_umac_addr(priv, priv->hw, ndev->dev_addr, 0);
+ 
++set_mac_error:
++      pm_runtime_put(priv->device);
++
+       return ret;
+ }
+ 
+@@ -4616,6 +4658,12 @@ static int stmmac_vlan_rx_kill_vid(struct net_device 
*ndev, __be16 proto, u16 vi
+       bool is_double = false;
+       int ret;
+ 
++      ret = pm_runtime_get_sync(priv->device);
++      if (ret < 0) {
++              pm_runtime_put_noidle(priv->device);
++              return ret;
++      }
++
+       if (be16_to_cpu(proto) == ETH_P_8021AD)
+               is_double = true;
+ 
+@@ -4624,10 +4672,15 @@ static int stmmac_vlan_rx_kill_vid(struct net_device 
*ndev, __be16 proto, u16 vi
+       if (priv->hw->num_vlan) {
+               ret = stmmac_del_hw_vlan_rx_fltr(priv, ndev, priv->hw, proto, 
vid);
+               if (ret)
+-                      return ret;
++                      goto del_vlan_error;
+       }
+ 
+-      return stmmac_vlan_update(priv, is_double);
++      ret = stmmac_vlan_update(priv, is_double);
++
++del_vlan_error:
++      pm_runtime_put(priv->device);
++
++      return ret;
+ }
+ 
+ static const struct net_device_ops stmmac_netdev_ops = {
+@@ -5066,6 +5119,10 @@ int stmmac_dvr_probe(struct device *device,
+ 
+       stmmac_check_pcs_mode(priv);
+ 
++      pm_runtime_get_noresume(device);
++      pm_runtime_set_active(device);
++      pm_runtime_enable(device);
++
+       if (priv->hw->pcs != STMMAC_PCS_TBI &&
+           priv->hw->pcs != STMMAC_PCS_RTBI) {
+               /* MDIO bus Registration */
+@@ -5103,6 +5160,11 @@ int stmmac_dvr_probe(struct device *device,
+       stmmac_init_fs(ndev);
+ #endif
+ 
++      /* Let pm_runtime_put() disable the clocks.
++       * If CONFIG_PM is not enabled, the clocks will stay powered.
++       */
++      pm_runtime_put(device);
++
+       return ret;
+ 
+ error_serdes_powerup:
+@@ -5152,8 +5214,8 @@ int stmmac_dvr_remove(struct device *dev)
+       phylink_destroy(priv->phylink);
+       if (priv->plat->stmmac_rst)
+               reset_control_assert(priv->plat->stmmac_rst);
+-      clk_disable_unprepare(priv->plat->pclk);
+-      clk_disable_unprepare(priv->plat->stmmac_clk);
++      pm_runtime_put(dev);
++      pm_runtime_disable(dev);
+       if (priv->hw->pcs != STMMAC_PCS_TBI &&
+           priv->hw->pcs != STMMAC_PCS_RTBI)
+               stmmac_mdio_unregister(ndev);
+@@ -5176,6 +5238,7 @@ int stmmac_suspend(struct device *dev)
+       struct net_device *ndev = dev_get_drvdata(dev);
+       struct stmmac_priv *priv = netdev_priv(ndev);
+       u32 chan;
++      int ret;
+ 
+       if (!ndev || !netif_running(ndev))
+               return 0;
+@@ -5219,8 +5282,11 @@ int stmmac_suspend(struct device *dev)
+               pinctrl_pm_select_sleep_state(priv->device);
+               /* Disable clock in case of PWM is off */
+               clk_disable_unprepare(priv->plat->clk_ptp_ref);
+-              clk_disable_unprepare(priv->plat->pclk);
+-              clk_disable_unprepare(priv->plat->stmmac_clk);
++              ret = pm_runtime_force_suspend(dev);
++              if (ret) {
++                      mutex_unlock(&priv->lock);
++                      return ret;
++              }
+       }
+       mutex_unlock(&priv->lock);
+ 
+@@ -5286,8 +5352,9 @@ int stmmac_resume(struct device *dev)
+       } else {
+               pinctrl_pm_select_default_state(priv->device);
+               /* enable the clk previously disabled */
+-              clk_prepare_enable(priv->plat->stmmac_clk);
+-              clk_prepare_enable(priv->plat->pclk);
++              ret = pm_runtime_force_resume(dev);
++              if (ret)
++                      return ret;
+               if (priv->plat->clk_ptp_ref)
+                       clk_prepare_enable(priv->plat->clk_ptp_ref);
+               /* reset the phy so that it's ready */
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+index 678726c62a8af..7c1a14b256da3 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+@@ -15,6 +15,7 @@
+ #include <linux/iopoll.h>
+ #include <linux/mii.h>
+ #include <linux/of_mdio.h>
++#include <linux/pm_runtime.h>
+ #include <linux/phy.h>
+ #include <linux/property.h>
+ #include <linux/slab.h>
+@@ -87,21 +88,29 @@ static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, 
int phyaddr, int phyreg)
+       u32 tmp, addr, value = MII_XGMAC_BUSY;
+       int ret;
+ 
++      ret = pm_runtime_get_sync(priv->device);
++      if (ret < 0) {
++              pm_runtime_put_noidle(priv->device);
++              return ret;
++      }
++
+       /* Wait until any existing MII operation is complete */
+       if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
+-                             !(tmp & MII_XGMAC_BUSY), 100, 10000))
+-              return -EBUSY;
++                             !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
++              ret = -EBUSY;
++              goto err_disable_clks;
++      }
+ 
+       if (phyreg & MII_ADDR_C45) {
+               phyreg &= ~MII_ADDR_C45;
+ 
+               ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
+               if (ret)
+-                      return ret;
++                      goto err_disable_clks;
+       } else {
+               ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
+               if (ret)
+-                      return ret;
++                      goto err_disable_clks;
+ 
+               value |= MII_XGMAC_SADDR;
+       }
+@@ -112,8 +121,10 @@ static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, 
int phyaddr, int phyreg)
+ 
+       /* Wait until any existing MII operation is complete */
+       if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
+-                             !(tmp & MII_XGMAC_BUSY), 100, 10000))
+-              return -EBUSY;
++                             !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
++              ret = -EBUSY;
++              goto err_disable_clks;
++      }
+ 
+       /* Set the MII address register to read */
+       writel(addr, priv->ioaddr + mii_address);
+@@ -121,11 +132,18 @@ static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, 
int phyaddr, int phyreg)
+ 
+       /* Wait until any existing MII operation is complete */
+       if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
+-                             !(tmp & MII_XGMAC_BUSY), 100, 10000))
+-              return -EBUSY;
++                             !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
++              ret = -EBUSY;
++              goto err_disable_clks;
++      }
+ 
+       /* Read the data from the MII data register */
+-      return readl(priv->ioaddr + mii_data) & GENMASK(15, 0);
++      ret = (int)readl(priv->ioaddr + mii_data) & GENMASK(15, 0);
++
++err_disable_clks:
++      pm_runtime_put(priv->device);
++
++      return ret;
+ }
+ 
+ static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr,
+@@ -138,21 +156,29 @@ static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, 
int phyaddr,
+       u32 addr, tmp, value = MII_XGMAC_BUSY;
+       int ret;
+ 
++      ret = pm_runtime_get_sync(priv->device);
++      if (ret < 0) {
++              pm_runtime_put_noidle(priv->device);
++              return ret;
++      }
++
+       /* Wait until any existing MII operation is complete */
+       if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
+-                             !(tmp & MII_XGMAC_BUSY), 100, 10000))
+-              return -EBUSY;
++                             !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
++              ret = -EBUSY;
++              goto err_disable_clks;
++      }
+ 
+       if (phyreg & MII_ADDR_C45) {
+               phyreg &= ~MII_ADDR_C45;
+ 
+               ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
+               if (ret)
+-                      return ret;
++                      goto err_disable_clks;
+       } else {
+               ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
+               if (ret)
+-                      return ret;
++                      goto err_disable_clks;
+ 
+               value |= MII_XGMAC_SADDR;
+       }
+@@ -164,16 +190,23 @@ static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, 
int phyaddr,
+ 
+       /* Wait until any existing MII operation is complete */
+       if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
+-                             !(tmp & MII_XGMAC_BUSY), 100, 10000))
+-              return -EBUSY;
++                             !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
++              ret = -EBUSY;
++              goto err_disable_clks;
++      }
+ 
+       /* Set the MII address register to write */
+       writel(addr, priv->ioaddr + mii_address);
+       writel(value, priv->ioaddr + mii_data);
+ 
+       /* Wait until any existing MII operation is complete */
+-      return readl_poll_timeout(priv->ioaddr + mii_data, tmp,
+-                                !(tmp & MII_XGMAC_BUSY), 100, 10000);
++      ret = readl_poll_timeout(priv->ioaddr + mii_data, tmp,
++                               !(tmp & MII_XGMAC_BUSY), 100, 10000);
++
++err_disable_clks:
++      pm_runtime_put(priv->device);
++
++      return ret;
+ }
+ 
+ /**
+@@ -196,6 +229,12 @@ static int stmmac_mdio_read(struct mii_bus *bus, int 
phyaddr, int phyreg)
+       int data = 0;
+       u32 v;
+ 
++      data = pm_runtime_get_sync(priv->device);
++      if (data < 0) {
++              pm_runtime_put_noidle(priv->device);
++              return data;
++      }
++
+       value |= (phyaddr << priv->hw->mii.addr_shift)
+               & priv->hw->mii.addr_mask;
+       value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
+@@ -216,19 +255,26 @@ static int stmmac_mdio_read(struct mii_bus *bus, int 
phyaddr, int phyreg)
+       }
+ 
+       if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
+-                             100, 10000))
+-              return -EBUSY;
++                             100, 10000)) {
++              data = -EBUSY;
++              goto err_disable_clks;
++      }
+ 
+       writel(data, priv->ioaddr + mii_data);
+       writel(value, priv->ioaddr + mii_address);
+ 
+       if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
+-                             100, 10000))
+-              return -EBUSY;
++                             100, 10000)) {
++              data = -EBUSY;
++              goto err_disable_clks;
++      }
+ 
+       /* Read the data from the MII data register */
+       data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
+ 
++err_disable_clks:
++      pm_runtime_put(priv->device);
++
+       return data;
+ }
+ 
+@@ -247,10 +293,16 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
+       struct stmmac_priv *priv = netdev_priv(ndev);
+       unsigned int mii_address = priv->hw->mii.addr;
+       unsigned int mii_data = priv->hw->mii.data;
++      int ret, data = phydata;
+       u32 value = MII_BUSY;
+-      int data = phydata;
+       u32 v;
+ 
++      ret = pm_runtime_get_sync(priv->device);
++      if (ret < 0) {
++              pm_runtime_put_noidle(priv->device);
++              return ret;
++      }
++
+       value |= (phyaddr << priv->hw->mii.addr_shift)
+               & priv->hw->mii.addr_mask;
+       value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
+@@ -275,16 +327,23 @@ static int stmmac_mdio_write(struct mii_bus *bus, int 
phyaddr, int phyreg,
+ 
+       /* Wait until any existing MII operation is complete */
+       if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
+-                             100, 10000))
+-              return -EBUSY;
++                             100, 10000)) {
++              ret = -EBUSY;
++              goto err_disable_clks;
++      }
+ 
+       /* Set the MII address register to write */
+       writel(data, priv->ioaddr + mii_data);
+       writel(value, priv->ioaddr + mii_address);
+ 
+       /* Wait until any existing MII operation is complete */
+-      return readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & 
MII_BUSY),
+-                                100, 10000);
++      ret = readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
++                               100, 10000);
++
++err_disable_clks:
++      pm_runtime_put(priv->device);
++
++      return ret;
+ }
+ 
+ /**
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+index 48186cd32ce10..035f9aef4308f 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+@@ -720,7 +720,6 @@ int stmmac_pltfr_remove(struct platform_device *pdev)
+ }
+ EXPORT_SYMBOL_GPL(stmmac_pltfr_remove);
+ 
+-#ifdef CONFIG_PM_SLEEP
+ /**
+  * stmmac_pltfr_suspend
+  * @dev: device pointer
+@@ -728,7 +727,7 @@ EXPORT_SYMBOL_GPL(stmmac_pltfr_remove);
+  * call the main suspend function and then, if required, on some platform, it
+  * can call an exit helper.
+  */
+-static int stmmac_pltfr_suspend(struct device *dev)
++static int __maybe_unused stmmac_pltfr_suspend(struct device *dev)
+ {
+       int ret;
+       struct net_device *ndev = dev_get_drvdata(dev);
+@@ -749,7 +748,7 @@ static int stmmac_pltfr_suspend(struct device *dev)
+  * the main resume function, on some platforms, it can call own init helper
+  * if required.
+  */
+-static int stmmac_pltfr_resume(struct device *dev)
++static int __maybe_unused stmmac_pltfr_resume(struct device *dev)
+ {
+       struct net_device *ndev = dev_get_drvdata(dev);
+       struct stmmac_priv *priv = netdev_priv(ndev);
+@@ -760,10 +759,29 @@ static int stmmac_pltfr_resume(struct device *dev)
+ 
+       return stmmac_resume(dev);
+ }
+-#endif /* CONFIG_PM_SLEEP */
+ 
+-SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops, stmmac_pltfr_suspend,
+-                                     stmmac_pltfr_resume);
++static int __maybe_unused stmmac_runtime_suspend(struct device *dev)
++{
++      struct net_device *ndev = dev_get_drvdata(dev);
++      struct stmmac_priv *priv = netdev_priv(ndev);
++
++      stmmac_bus_clks_config(priv, false);
++
++      return 0;
++}
++
++static int __maybe_unused stmmac_runtime_resume(struct device *dev)
++{
++      struct net_device *ndev = dev_get_drvdata(dev);
++      struct stmmac_priv *priv = netdev_priv(ndev);
++
++      return stmmac_bus_clks_config(priv, true);
++}
++
++const struct dev_pm_ops stmmac_pltfr_pm_ops = {
++      SET_SYSTEM_SLEEP_PM_OPS(stmmac_pltfr_suspend, stmmac_pltfr_resume)
++      SET_RUNTIME_PM_OPS(stmmac_runtime_suspend, stmmac_runtime_resume, NULL)
++};
+ EXPORT_SYMBOL_GPL(stmmac_pltfr_pm_ops);
+ 
+ MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet platform support");
+diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
+index a7a1c74113483..db7475dc601f5 100644
+--- a/drivers/pci/msi.c
++++ b/drivers/pci/msi.c
+@@ -396,18 +396,6 @@ static void free_msi_irqs(struct pci_dev *dev)
+                       for (i = 0; i < entry->nvec_used; i++)
+                               BUG_ON(irq_has_action(entry->irq + i));
+ 
+-      pci_msi_teardown_msi_irqs(dev);
+-
+-      list_for_each_entry_safe(entry, tmp, msi_list, list) {
+-              if (entry->msi_attrib.is_msix) {
+-                      if (list_is_last(&entry->list, msi_list))
+-                              iounmap(entry->mask_base);
+-              }
+-
+-              list_del(&entry->list);
+-              free_msi_entry(entry);
+-      }
+-
+       if (dev->msi_irq_groups) {
+               sysfs_remove_groups(&dev->dev.kobj, dev->msi_irq_groups);
+               msi_attrs = dev->msi_irq_groups[0]->attrs;
+@@ -423,6 +411,18 @@ static void free_msi_irqs(struct pci_dev *dev)
+               kfree(dev->msi_irq_groups);
+               dev->msi_irq_groups = NULL;
+       }
++
++      pci_msi_teardown_msi_irqs(dev);
++
++      list_for_each_entry_safe(entry, tmp, msi_list, list) {
++              if (entry->msi_attrib.is_msix) {
++                      if (list_is_last(&entry->list, msi_list))
++                              iounmap(entry->mask_base);
++              }
++
++              list_del(&entry->list);
++              free_msi_entry(entry);
++      }
+ }
+ 
+ static void pci_intx_for_msi(struct pci_dev *dev, int enable)
+@@ -592,6 +592,9 @@ msi_setup_entry(struct pci_dev *dev, int nvec, struct 
irq_affinity *affd)
+               goto out;
+ 
+       pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
++      /* Lies, damned lies, and MSIs */
++      if (dev->dev_flags & PCI_DEV_FLAGS_HAS_MSI_MASKING)
++              control |= PCI_MSI_FLAGS_MASKBIT;
+ 
+       entry->msi_attrib.is_msix       = 0;
+       entry->msi_attrib.is_64         = !!(control & PCI_MSI_FLAGS_64BIT);
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index fb91b2d7b1c59..bb863ddb59bfc 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -5756,3 +5756,9 @@ static void apex_pci_fixup_class(struct pci_dev *pdev)
+ }
+ DECLARE_PCI_FIXUP_CLASS_HEADER(0x1ac1, 0x089a,
+                              PCI_CLASS_NOT_DEFINED, 8, apex_pci_fixup_class);
++
++static void nvidia_ion_ahci_fixup(struct pci_dev *pdev)
++{
++      pdev->dev_flags |= PCI_DEV_FLAGS_HAS_MSI_MASKING;
++}
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0ab8, nvidia_ion_ahci_fixup);
+diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
+index 6379f26a335f6..9233f7e744544 100644
+--- a/drivers/thermal/thermal_of.c
++++ b/drivers/thermal/thermal_of.c
+@@ -89,7 +89,7 @@ static int of_thermal_get_temp(struct thermal_zone_device 
*tz,
+ {
+       struct __thermal_zone *data = tz->devdata;
+ 
+-      if (!data->ops->get_temp)
++      if (!data->ops || !data->ops->get_temp)
+               return -EINVAL;
+ 
+       return data->ops->get_temp(data->sensor_data, temp);
+@@ -186,6 +186,9 @@ static int of_thermal_set_emul_temp(struct 
thermal_zone_device *tz,
+ {
+       struct __thermal_zone *data = tz->devdata;
+ 
++      if (!data->ops || !data->ops->set_emul_temp)
++              return -EINVAL;
++
+       return data->ops->set_emul_temp(data->sensor_data, temp);
+ }
+ 
+@@ -194,7 +197,7 @@ static int of_thermal_get_trend(struct thermal_zone_device 
*tz, int trip,
+ {
+       struct __thermal_zone *data = tz->devdata;
+ 
+-      if (!data->ops->get_trend)
++      if (!data->ops || !data->ops->get_trend)
+               return -EINVAL;
+ 
+       return data->ops->get_trend(data->sensor_data, trip, trend);
+@@ -301,7 +304,7 @@ static int of_thermal_set_trip_temp(struct 
thermal_zone_device *tz, int trip,
+       if (trip >= data->ntrips || trip < 0)
+               return -EDOM;
+ 
+-      if (data->ops->set_trip_temp) {
++      if (data->ops && data->ops->set_trip_temp) {
+               int ret;
+ 
+               ret = data->ops->set_trip_temp(data->sensor_data, trip, temp);
+diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c
+index 86fd3bf62af61..8cb2cf612e49b 100644
+--- a/fs/erofs/zdata.c
++++ b/fs/erofs/zdata.c
+@@ -278,11 +278,10 @@ static inline bool z_erofs_try_inplace_io(struct 
z_erofs_collector *clt,
+ 
+ /* callers must be with collection lock held */
+ static int z_erofs_attach_page(struct z_erofs_collector *clt,
+-                             struct page *page,
+-                             enum z_erofs_page_type type)
++                             struct page *page, enum z_erofs_page_type type,
++                             bool pvec_safereuse)
+ {
+       int ret;
+-      bool occupied;
+ 
+       /* give priority for inplaceio */
+       if (clt->mode >= COLLECT_PRIMARY &&
+@@ -290,10 +289,9 @@ static int z_erofs_attach_page(struct z_erofs_collector 
*clt,
+           z_erofs_try_inplace_io(clt, page))
+               return 0;
+ 
+-      ret = z_erofs_pagevec_enqueue(&clt->vector,
+-                                    page, type, &occupied);
++      ret = z_erofs_pagevec_enqueue(&clt->vector, page, type,
++                                    pvec_safereuse);
+       clt->cl->vcnt += (unsigned int)ret;
+-
+       return ret ? 0 : -EAGAIN;
+ }
+ 
+@@ -647,7 +645,8 @@ hitted:
+               tight &= (clt->mode >= COLLECT_PRIMARY_FOLLOWED);
+ 
+ retry:
+-      err = z_erofs_attach_page(clt, page, page_type);
++      err = z_erofs_attach_page(clt, page, page_type,
++                                clt->mode >= COLLECT_PRIMARY_FOLLOWED);
+       /* should allocate an additional staging page for pagevec */
+       if (err == -EAGAIN) {
+               struct page *const newpage =
+@@ -655,7 +654,7 @@ retry:
+ 
+               newpage->mapping = Z_EROFS_MAPPING_STAGING;
+               err = z_erofs_attach_page(clt, newpage,
+-                                        Z_EROFS_PAGE_TYPE_EXCLUSIVE);
++                                        Z_EROFS_PAGE_TYPE_EXCLUSIVE, true);
+               if (!err)
+                       goto retry;
+       }
+diff --git a/fs/erofs/zpvec.h b/fs/erofs/zpvec.h
+index 1d67cbd387042..52898176ef31d 100644
+--- a/fs/erofs/zpvec.h
++++ b/fs/erofs/zpvec.h
+@@ -108,12 +108,17 @@ static inline void z_erofs_pagevec_ctor_init(struct 
z_erofs_pagevec_ctor *ctor,
+ static inline bool z_erofs_pagevec_enqueue(struct z_erofs_pagevec_ctor *ctor,
+                                          struct page *page,
+                                          enum z_erofs_page_type type,
+-                                         bool *occupied)
++                                         bool pvec_safereuse)
+ {
+-      *occupied = false;
+-      if (!ctor->next && type)
+-              if (ctor->index + 1 == ctor->nr)
++      if (!ctor->next) {
++              /* some pages cannot be reused as pvec safely without I/O */
++              if (type == Z_EROFS_PAGE_TYPE_EXCLUSIVE && !pvec_safereuse)
++                      type = Z_EROFS_VLE_PAGE_TYPE_TAIL_SHARED;
++
++              if (type != Z_EROFS_PAGE_TYPE_EXCLUSIVE &&
++                  ctor->index + 1 == ctor->nr)
+                       return false;
++      }
+ 
+       if (ctor->index >= ctor->nr)
+               z_erofs_pagevec_ctor_pagedown(ctor, false);
+@@ -125,7 +130,6 @@ static inline bool z_erofs_pagevec_enqueue(struct 
z_erofs_pagevec_ctor *ctor,
+       /* should remind that collector->next never equal to 1, 2 */
+       if (type == (uintptr_t)ctor->next) {
+               ctor->next = page;
+-              *occupied = true;
+       }
+       ctor->pages[ctor->index++] = tagptr_fold(erofs_vtptr_t, page, type);
+       return true;
+diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
+index 4ba17736b614f..98fdf5a31fd66 100644
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -59,6 +59,14 @@ struct blk_keyslot_manager;
+  */
+ #define BLKCG_MAX_POLS                5
+ 
++static inline int blk_validate_block_size(unsigned int bsize)
++{
++      if (bsize < 512 || bsize > PAGE_SIZE || !is_power_of_2(bsize))
++              return -EINVAL;
++
++      return 0;
++}
++
+ typedef void (rq_end_io_fn)(struct request *, blk_status_t);
+ 
+ /*
+diff --git a/include/linux/pci.h b/include/linux/pci.h
+index a55097b4d9927..4519bd12643f6 100644
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -227,6 +227,8 @@ enum pci_dev_flags {
+       PCI_DEV_FLAGS_NO_FLR_RESET = (__force pci_dev_flags_t) (1 << 10),
+       /* Don't use Relaxed Ordering for TLPs directed at this device */
+       PCI_DEV_FLAGS_NO_RELAXED_ORDERING = (__force pci_dev_flags_t) (1 << 11),
++      /* Device does honor MSI masking despite saying otherwise */
++      PCI_DEV_FLAGS_HAS_MSI_MASKING = (__force pci_dev_flags_t) (1 << 12),
+ };
+ 
+ enum pci_irq_reroute_variant {
+diff --git a/init/main.c b/init/main.c
+index dd26a42e80a87..4fe58ed4aca7b 100644
+--- a/init/main.c
++++ b/init/main.c
+@@ -380,6 +380,7 @@ static char * __init xbc_make_cmdline(const char *key)
+       ret = xbc_snprint_cmdline(new_cmdline, len + 1, root);
+       if (ret < 0 || ret > len) {
+               pr_err("Failed to print extra kernel cmdline.\n");
++              memblock_free(__pa(new_cmdline), len + 1);
+               return NULL;
+       }
+ 
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index c811519261710..908417736f4e9 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -7036,7 +7036,6 @@ void perf_output_sample(struct perf_output_handle 
*handle,
+ static u64 perf_virt_to_phys(u64 virt)
+ {
+       u64 phys_addr = 0;
+-      struct page *p = NULL;
+ 
+       if (!virt)
+               return 0;
+@@ -7055,14 +7054,15 @@ static u64 perf_virt_to_phys(u64 virt)
+                * If failed, leave phys_addr as 0.
+                */
+               if (current->mm != NULL) {
++                      struct page *p;
++
+                       pagefault_disable();
+-                      if (get_user_page_fast_only(virt, 0, &p))
++                      if (get_user_page_fast_only(virt, 0, &p)) {
+                               phys_addr = page_to_phys(p) + virt % PAGE_SIZE;
++                              put_page(p);
++                      }
+                       pagefault_enable();
+               }
+-
+-              if (p)
+-                      put_page(p);
+       }
+ 
+       return phys_addr;
+diff --git a/scripts/lld-version.sh b/scripts/lld-version.sh
+index d70edb4d8a4f2..f1eeee450a23c 100755
+--- a/scripts/lld-version.sh
++++ b/scripts/lld-version.sh
+@@ -6,15 +6,32 @@
+ # Print the linker version of `ld.lld' in a 5 or 6-digit form
+ # such as `100001' for ld.lld 10.0.1 etc.
+ 
+-linker_string="$($* --version)"
++set -e
+ 
+-if ! ( echo $linker_string | grep -q LLD ); then
++# Convert the version string x.y.z to a canonical 5 or 6-digit form.
++get_canonical_version()
++{
++      IFS=.
++      set -- $1
++
++      # If the 2nd or 3rd field is missing, fill it with a zero.
++      echo $((10000 * $1 + 100 * ${2:-0} + ${3:-0}))
++}
++
++# Get the first line of the --version output.
++IFS='
++'
++set -- $(LC_ALL=C "$@" --version)
++
++# Split the line on spaces.
++IFS=' '
++set -- $1
++
++while [ $# -gt 1 -a "$1" != "LLD" ]; do
++      shift
++done
++if [ "$1" = LLD ]; then
++      echo $(get_canonical_version ${2%-*})
++else
+       echo 0
+-      exit 1
+ fi
+-
+-VERSION=$(echo $linker_string | cut -d ' ' -f 2)
+-MAJOR=$(echo $VERSION | cut -d . -f 1)
+-MINOR=$(echo $VERSION | cut -d . -f 2)
+-PATCHLEVEL=$(echo $VERSION | cut -d . -f 3)
+-printf "%d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL
+diff --git a/security/Kconfig b/security/Kconfig
+index 7561f6f99f1d2..0548db16c49dc 100644
+--- a/security/Kconfig
++++ b/security/Kconfig
+@@ -191,6 +191,9 @@ config HARDENED_USERCOPY_PAGESPAN
+ config FORTIFY_SOURCE
+       bool "Harden common str/mem functions against buffer overflows"
+       depends on ARCH_HAS_FORTIFY_SOURCE
++      # https://bugs.llvm.org/show_bug.cgi?id=50322
++      # https://bugs.llvm.org/show_bug.cgi?id=41459
++      depends on !CC_IS_CLANG
+       help
+         Detect overflows of buffers in common string and memory functions
+         where the compiler can determine and validate the buffer sizes.
+diff --git a/tools/testing/selftests/x86/iopl.c 
b/tools/testing/selftests/x86/iopl.c
+index bab2f6e06b63d..7e3e09c1abac6 100644
+--- a/tools/testing/selftests/x86/iopl.c
++++ b/tools/testing/selftests/x86/iopl.c
+@@ -85,48 +85,88 @@ static void expect_gp_outb(unsigned short port)
+       printf("[OK]\toutb to 0x%02hx failed\n", port);
+ }
+ 
+-static bool try_cli(void)
++#define RET_FAULTED   0
++#define RET_FAIL      1
++#define RET_EMUL      2
++
++static int try_cli(void)
+ {
++      unsigned long flags;
++
+       sethandler(SIGSEGV, sigsegv, SA_RESETHAND);
+       if (sigsetjmp(jmpbuf, 1) != 0) {
+-              return false;
++              return RET_FAULTED;
+       } else {
+-              asm volatile ("cli");
+-              return true;
++              asm volatile("cli; pushf; pop %[flags]"
++                              : [flags] "=rm" (flags));
++
++              /* X86_FLAGS_IF */
++              if (!(flags & (1 << 9)))
++                      return RET_FAIL;
++              else
++                      return RET_EMUL;
+       }
+       clearhandler(SIGSEGV);
+ }
+ 
+-static bool try_sti(void)
++static int try_sti(bool irqs_off)
+ {
++      unsigned long flags;
++
+       sethandler(SIGSEGV, sigsegv, SA_RESETHAND);
+       if (sigsetjmp(jmpbuf, 1) != 0) {
+-              return false;
++              return RET_FAULTED;
+       } else {
+-              asm volatile ("sti");
+-              return true;
++              asm volatile("sti; pushf; pop %[flags]"
++                              : [flags] "=rm" (flags));
++
++              /* X86_FLAGS_IF */
++              if (irqs_off && (flags & (1 << 9)))
++                      return RET_FAIL;
++              else
++                      return RET_EMUL;
+       }
+       clearhandler(SIGSEGV);
+ }
+ 
+-static void expect_gp_sti(void)
++static void expect_gp_sti(bool irqs_off)
+ {
+-      if (try_sti()) {
++      int ret = try_sti(irqs_off);
++
++      switch (ret) {
++      case RET_FAULTED:
++              printf("[OK]\tSTI faulted\n");
++              break;
++      case RET_EMUL:
++              printf("[OK]\tSTI NOPped\n");
++              break;
++      default:
+               printf("[FAIL]\tSTI worked\n");
+               nerrs++;
+-      } else {
+-              printf("[OK]\tSTI faulted\n");
+       }
+ }
+ 
+-static void expect_gp_cli(void)
++/*
++ * Returns whether it managed to disable interrupts.
++ */
++static bool test_cli(void)
+ {
+-      if (try_cli()) {
++      int ret = try_cli();
++
++      switch (ret) {
++      case RET_FAULTED:
++              printf("[OK]\tCLI faulted\n");
++              break;
++      case RET_EMUL:
++              printf("[OK]\tCLI NOPped\n");
++              break;
++      default:
+               printf("[FAIL]\tCLI worked\n");
+               nerrs++;
+-      } else {
+-              printf("[OK]\tCLI faulted\n");
++              return true;
+       }
++
++      return false;
+ }
+ 
+ int main(void)
+@@ -152,8 +192,7 @@ int main(void)
+       }
+ 
+       /* Make sure that CLI/STI are blocked even with IOPL level 3 */
+-      expect_gp_cli();
+-      expect_gp_sti();
++      expect_gp_sti(test_cli());
+       expect_ok_outb(0x80);
+ 
+       /* Establish an I/O bitmap to test the restore */
+@@ -204,8 +243,7 @@ int main(void)
+       printf("[RUN]\tparent: write to 0x80 (should fail)\n");
+ 
+       expect_gp_outb(0x80);
+-      expect_gp_cli();
+-      expect_gp_sti();
++      expect_gp_sti(test_cli());
+ 
+       /* Test the capability checks. */
+       printf("\tiopl(3)\n");

Reply via email to