summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pagano <mpagano@gentoo.org>2021-11-21 15:42:40 -0500
committerMike Pagano <mpagano@gentoo.org>2021-11-21 15:42:40 -0500
commitffcf9f68f9a2e99641b96e1629e477e770e99f48 (patch)
tree1d0733baa5daa8b3366bf787c472d2856ef268b0
parentLinux patch 5.10.80 (diff)
downloadlinux-patches-ffcf9f68f9a2e99641b96e1629e477e770e99f48.tar.gz
linux-patches-ffcf9f68f9a2e99641b96e1629e477e770e99f48.tar.bz2
linux-patches-ffcf9f68f9a2e99641b96e1629e477e770e99f48.zip
Linux patch 5.10.815.10-88
Signed-off-by: Mike Pagano <mpagano@gentoo.org>
-rw-r--r--0000_README4
-rw-r--r--1080_linux-5.10.81.patch1173
2 files changed, 1177 insertions, 0 deletions
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");