summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pagano <mpagano@gentoo.org>2020-10-14 16:38:37 -0400
committerMike Pagano <mpagano@gentoo.org>2020-10-14 16:38:37 -0400
commit0d84d996394498a013226bca10c8c5e84cca985e (patch)
treeec11f705cce0b130cc429163b081be68243f5572
parentLinux patch 5.8.14 (diff)
downloadlinux-patches-0d84d996394498a013226bca10c8c5e84cca985e.tar.gz
linux-patches-0d84d996394498a013226bca10c8c5e84cca985e.tar.bz2
linux-patches-0d84d996394498a013226bca10c8c5e84cca985e.zip
Linux patch 5.8.155.8-18
Signed-off-by: Mike Pagano <mpagano@gentoo.org>
-rw-r--r--0000_README4
-rw-r--r--1014_linux-5.8.15.patch7265
2 files changed, 7269 insertions, 0 deletions
diff --git a/0000_README b/0000_README
index 6e16f1d7..34004944 100644
--- a/0000_README
+++ b/0000_README
@@ -99,6 +99,10 @@ Patch: 1013_linux-5.8.14.patch
From: http://www.kernel.org
Desc: Linux 5.8.14
+Patch: 1014_linux-5.8.15.patch
+From: http://www.kernel.org
+Desc: Linux 5.8.15
+
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/1014_linux-5.8.15.patch b/1014_linux-5.8.15.patch
new file mode 100644
index 00000000..0710af71
--- /dev/null
+++ b/1014_linux-5.8.15.patch
@@ -0,0 +1,7265 @@
+diff --git a/Makefile b/Makefile
+index 33ceda527e5ef..6c787cd1cb514 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ VERSION = 5
+ PATCHLEVEL = 8
+-SUBLEVEL = 14
++SUBLEVEL = 15
+ EXTRAVERSION =
+ NAME = Kleptomaniac Octopus
+
+diff --git a/arch/arm64/crypto/aes-neonbs-core.S b/arch/arm64/crypto/aes-neonbs-core.S
+index b357164379f6d..63a52ad9a75c0 100644
+--- a/arch/arm64/crypto/aes-neonbs-core.S
++++ b/arch/arm64/crypto/aes-neonbs-core.S
+@@ -788,7 +788,7 @@ SYM_FUNC_START_LOCAL(__xts_crypt8)
+
+ 0: mov bskey, x21
+ mov rounds, x22
+- br x7
++ br x16
+ SYM_FUNC_END(__xts_crypt8)
+
+ .macro __xts_crypt, do8, o0, o1, o2, o3, o4, o5, o6, o7
+@@ -806,7 +806,7 @@ SYM_FUNC_END(__xts_crypt8)
+ uzp1 v30.4s, v30.4s, v25.4s
+ ld1 {v25.16b}, [x24]
+
+-99: adr x7, \do8
++99: adr x16, \do8
+ bl __xts_crypt8
+
+ ldp q16, q17, [sp, #.Lframe_local_offset]
+diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
+index e229d95f470b8..7c1dadf14f567 100644
+--- a/arch/riscv/mm/init.c
++++ b/arch/riscv/mm/init.c
+@@ -515,6 +515,7 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
+ #else
+ dtb_early_va = (void *)dtb_pa;
+ #endif
++ dtb_early_pa = dtb_pa;
+ }
+
+ static inline void setup_vm_final(void)
+diff --git a/block/partitions/ibm.c b/block/partitions/ibm.c
+index d6e18df9c53c6..4b044e620d353 100644
+--- a/block/partitions/ibm.c
++++ b/block/partitions/ibm.c
+@@ -305,8 +305,6 @@ int ibm_partition(struct parsed_partitions *state)
+ if (!disk->fops->getgeo)
+ goto out_exit;
+ fn = symbol_get(dasd_biodasdinfo);
+- if (!fn)
+- goto out_exit;
+ blocksize = bdev_logical_block_size(bdev);
+ if (blocksize <= 0)
+ goto out_symbol;
+@@ -326,7 +324,7 @@ int ibm_partition(struct parsed_partitions *state)
+ geo->start = get_start_sect(bdev);
+ if (disk->fops->getgeo(bdev, geo))
+ goto out_freeall;
+- if (fn(disk, info)) {
++ if (!fn || fn(disk, info)) {
+ kfree(info);
+ info = NULL;
+ }
+@@ -370,7 +368,8 @@ out_nolab:
+ out_nogeo:
+ kfree(info);
+ out_symbol:
+- symbol_put(dasd_biodasdinfo);
++ if (fn)
++ symbol_put(dasd_biodasdinfo);
+ out_exit:
+ return res;
+ }
+diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
+index ef722f04f88a9..72108404718fe 100644
+--- a/block/scsi_ioctl.c
++++ b/block/scsi_ioctl.c
+@@ -651,6 +651,7 @@ struct compat_cdrom_generic_command {
+ compat_int_t stat;
+ compat_caddr_t sense;
+ unsigned char data_direction;
++ unsigned char pad[3];
+ compat_int_t quiet;
+ compat_int_t timeout;
+ compat_caddr_t reserved[1];
+diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
+index 6e813b13d6988..02154d8b1c0d5 100644
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -838,7 +838,7 @@ static __poll_t lineevent_poll(struct file *filep,
+
+ static ssize_t lineevent_get_size(void)
+ {
+-#ifdef __x86_64__
++#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
+ /* i386 has no padding after 'id' */
+ if (in_ia32_syscall()) {
+ struct compat_gpioeevent_data {
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+index e59c01a83dace..9a3267f06376f 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+@@ -1052,6 +1052,7 @@ static int amdgpu_ttm_tt_pin_userptr(struct ttm_tt *ttm)
+
+ release_sg:
+ kfree(ttm->sg);
++ ttm->sg = NULL;
+ return r;
+ }
+
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
+index 949d10ef83040..6dd1f3f8d9903 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
+@@ -568,7 +568,7 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct
+ int i = 0;
+
+ hdcp_work = kcalloc(max_caps, sizeof(*hdcp_work), GFP_KERNEL);
+- if (hdcp_work == NULL)
++ if (ZERO_OR_NULL_PTR(hdcp_work))
+ return NULL;
+
+ hdcp_work->srm = kcalloc(PSP_HDCP_SRM_FIRST_GEN_MAX_SIZE, sizeof(*hdcp_work->srm), GFP_KERNEL);
+diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c
+index 9ee8cf8267c88..43f7adff6cb74 100644
+--- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c
++++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c
+@@ -563,6 +563,8 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
+ struct smu10_hwmgr *data = hwmgr->backend;
+ uint32_t min_sclk = hwmgr->display_config->min_core_set_clock;
+ uint32_t min_mclk = hwmgr->display_config->min_mem_set_clock/100;
++ uint32_t index_fclk = data->clock_vol_info.vdd_dep_on_fclk->count - 1;
++ uint32_t index_socclk = data->clock_vol_info.vdd_dep_on_socclk->count - 1;
+
+ if (hwmgr->smu_version < 0x1E3700) {
+ pr_info("smu firmware version too old, can not set dpm level\n");
+@@ -676,13 +678,13 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
+ smum_send_msg_to_smc_with_parameter(hwmgr,
+ PPSMC_MSG_SetHardMinFclkByFreq,
+ hwmgr->display_config->num_display > 3 ?
+- SMU10_UMD_PSTATE_PEAK_FCLK :
++ data->clock_vol_info.vdd_dep_on_fclk->entries[0].clk :
+ min_mclk,
+ NULL);
+
+ smum_send_msg_to_smc_with_parameter(hwmgr,
+ PPSMC_MSG_SetHardMinSocclkByFreq,
+- SMU10_UMD_PSTATE_MIN_SOCCLK,
++ data->clock_vol_info.vdd_dep_on_socclk->entries[0].clk,
+ NULL);
+ smum_send_msg_to_smc_with_parameter(hwmgr,
+ PPSMC_MSG_SetHardMinVcn,
+@@ -695,11 +697,11 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
+ NULL);
+ smum_send_msg_to_smc_with_parameter(hwmgr,
+ PPSMC_MSG_SetSoftMaxFclkByFreq,
+- SMU10_UMD_PSTATE_PEAK_FCLK,
++ data->clock_vol_info.vdd_dep_on_fclk->entries[index_fclk].clk,
+ NULL);
+ smum_send_msg_to_smc_with_parameter(hwmgr,
+ PPSMC_MSG_SetSoftMaxSocclkByFreq,
+- SMU10_UMD_PSTATE_PEAK_SOCCLK,
++ data->clock_vol_info.vdd_dep_on_socclk->entries[index_socclk].clk,
+ NULL);
+ smum_send_msg_to_smc_with_parameter(hwmgr,
+ PPSMC_MSG_SetSoftMaxVcn,
+diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
+index c002f89685073..9682f30ab6f68 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
++++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
+@@ -176,6 +176,8 @@ void
+ nouveau_mem_del(struct ttm_mem_reg *reg)
+ {
+ struct nouveau_mem *mem = nouveau_mem(reg);
++ if (!mem)
++ return;
+ nouveau_mem_fini(mem);
+ kfree(reg->mm_node);
+ reg->mm_node = NULL;
+diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+index 5b90c2a1bf3d3..7c2e5db840be5 100644
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+@@ -3149,6 +3149,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
+ case 0x168: device->chip = &nv168_chipset; break;
+ default:
+ nvdev_error(device, "unknown chipset (%08x)\n", boot0);
++ ret = -ENODEV;
+ goto done;
+ }
+
+diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c
+index c5dec572fc48e..ef73a42577cc7 100644
+--- a/drivers/i2c/busses/i2c-meson.c
++++ b/drivers/i2c/busses/i2c-meson.c
+@@ -5,6 +5,7 @@
+ * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
+ */
+
++#include <linux/bitfield.h>
+ #include <linux/clk.h>
+ #include <linux/completion.h>
+ #include <linux/i2c.h>
+@@ -33,12 +34,17 @@
+ #define REG_CTRL_ACK_IGNORE BIT(1)
+ #define REG_CTRL_STATUS BIT(2)
+ #define REG_CTRL_ERROR BIT(3)
+-#define REG_CTRL_CLKDIV_SHIFT 12
+-#define REG_CTRL_CLKDIV_MASK GENMASK(21, 12)
+-#define REG_CTRL_CLKDIVEXT_SHIFT 28
+-#define REG_CTRL_CLKDIVEXT_MASK GENMASK(29, 28)
++#define REG_CTRL_CLKDIV GENMASK(21, 12)
++#define REG_CTRL_CLKDIVEXT GENMASK(29, 28)
++
++#define REG_SLV_ADDR GENMASK(7, 0)
++#define REG_SLV_SDA_FILTER GENMASK(10, 8)
++#define REG_SLV_SCL_FILTER GENMASK(13, 11)
++#define REG_SLV_SCL_LOW GENMASK(27, 16)
++#define REG_SLV_SCL_LOW_EN BIT(28)
+
+ #define I2C_TIMEOUT_MS 500
++#define FILTER_DELAY 15
+
+ enum {
+ TOKEN_END = 0,
+@@ -133,19 +139,24 @@ static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq)
+ unsigned long clk_rate = clk_get_rate(i2c->clk);
+ unsigned int div;
+
+- div = DIV_ROUND_UP(clk_rate, freq * i2c->data->div_factor);
++ div = DIV_ROUND_UP(clk_rate, freq);
++ div -= FILTER_DELAY;
++ div = DIV_ROUND_UP(div, i2c->data->div_factor);
+
+ /* clock divider has 12 bits */
+- if (div >= (1 << 12)) {
++ if (div > GENMASK(11, 0)) {
+ dev_err(i2c->dev, "requested bus frequency too low\n");
+- div = (1 << 12) - 1;
++ div = GENMASK(11, 0);
+ }
+
+- meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV_MASK,
+- (div & GENMASK(9, 0)) << REG_CTRL_CLKDIV_SHIFT);
++ meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV,
++ FIELD_PREP(REG_CTRL_CLKDIV, div & GENMASK(9, 0)));
++
++ meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT,
++ FIELD_PREP(REG_CTRL_CLKDIVEXT, div >> 10));
+
+- meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT_MASK,
+- (div >> 10) << REG_CTRL_CLKDIVEXT_SHIFT);
++ /* Disable HIGH/LOW mode */
++ meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_SCL_LOW_EN, 0);
+
+ dev_dbg(i2c->dev, "%s: clk %lu, freq %u, div %u\n", __func__,
+ clk_rate, freq, div);
+@@ -280,7 +291,10 @@ static void meson_i2c_do_start(struct meson_i2c *i2c, struct i2c_msg *msg)
+ token = (msg->flags & I2C_M_RD) ? TOKEN_SLAVE_ADDR_READ :
+ TOKEN_SLAVE_ADDR_WRITE;
+
+- writel(msg->addr << 1, i2c->regs + REG_SLAVE_ADDR);
++
++ meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_ADDR,
++ FIELD_PREP(REG_SLV_ADDR, msg->addr << 1));
++
+ meson_i2c_add_token(i2c, TOKEN_START);
+ meson_i2c_add_token(i2c, token);
+ }
+@@ -357,16 +371,12 @@ static int meson_i2c_xfer_messages(struct i2c_adapter *adap,
+ struct meson_i2c *i2c = adap->algo_data;
+ int i, ret = 0;
+
+- clk_enable(i2c->clk);
+-
+ for (i = 0; i < num; i++) {
+ ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1, atomic);
+ if (ret)
+ break;
+ }
+
+- clk_disable(i2c->clk);
+-
+ return ret ?: i;
+ }
+
+@@ -435,7 +445,7 @@ static int meson_i2c_probe(struct platform_device *pdev)
+ return ret;
+ }
+
+- ret = clk_prepare(i2c->clk);
++ ret = clk_prepare_enable(i2c->clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "can't prepare clock\n");
+ return ret;
+@@ -457,10 +467,14 @@ static int meson_i2c_probe(struct platform_device *pdev)
+
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret < 0) {
+- clk_unprepare(i2c->clk);
++ clk_disable_unprepare(i2c->clk);
+ return ret;
+ }
+
++ /* Disable filtering */
++ meson_i2c_set_mask(i2c, REG_SLAVE_ADDR,
++ REG_SLV_SDA_FILTER | REG_SLV_SCL_FILTER, 0);
++
+ meson_i2c_set_clk_div(i2c, timings.bus_freq_hz);
+
+ return 0;
+@@ -471,7 +485,7 @@ static int meson_i2c_remove(struct platform_device *pdev)
+ struct meson_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adap);
+- clk_unprepare(i2c->clk);
++ clk_disable_unprepare(i2c->clk);
+
+ return 0;
+ }
+diff --git a/drivers/i2c/busses/i2c-owl.c b/drivers/i2c/busses/i2c-owl.c
+index 672f1f239bd6f..a163b8f308c14 100644
+--- a/drivers/i2c/busses/i2c-owl.c
++++ b/drivers/i2c/busses/i2c-owl.c
+@@ -176,6 +176,9 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
+ fifostat = readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT);
+ if (fifostat & OWL_I2C_FIFOSTAT_RNB) {
+ i2c_dev->err = -ENXIO;
++ /* Clear NACK error bit by writing "1" */
++ owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOSTAT,
++ OWL_I2C_FIFOSTAT_RNB, true);
+ goto stop;
+ }
+
+@@ -183,6 +186,9 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
+ stat = readl(i2c_dev->base + OWL_I2C_REG_STAT);
+ if (stat & OWL_I2C_STAT_BEB) {
+ i2c_dev->err = -EIO;
++ /* Clear BUS error bit by writing "1" */
++ owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT,
++ OWL_I2C_STAT_BEB, true);
+ goto stop;
+ }
+
+diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
+index 305f0160506a0..8a36d78fed63a 100644
+--- a/drivers/input/misc/ati_remote2.c
++++ b/drivers/input/misc/ati_remote2.c
+@@ -68,7 +68,7 @@ static int ati_remote2_get_channel_mask(char *buffer,
+ {
+ pr_debug("%s()\n", __func__);
+
+- return sprintf(buffer, "0x%04x", *(unsigned int *)kp->arg);
++ return sprintf(buffer, "0x%04x\n", *(unsigned int *)kp->arg);
+ }
+
+ static int ati_remote2_set_mode_mask(const char *val,
+@@ -84,7 +84,7 @@ static int ati_remote2_get_mode_mask(char *buffer,
+ {
+ pr_debug("%s()\n", __func__);
+
+- return sprintf(buffer, "0x%02x", *(unsigned int *)kp->arg);
++ return sprintf(buffer, "0x%02x\n", *(unsigned int *)kp->arg);
+ }
+
+ static unsigned int channel_mask = ATI_REMOTE2_MAX_CHANNEL_MASK;
+diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
+index fbe0b0cc56edf..24a84d294fd01 100644
+--- a/drivers/iommu/intel/iommu.c
++++ b/drivers/iommu/intel/iommu.c
+@@ -2617,7 +2617,7 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu,
+ }
+
+ /* Setup the PASID entry for requests without PASID: */
+- spin_lock(&iommu->lock);
++ spin_lock_irqsave(&iommu->lock, flags);
+ if (hw_pass_through && domain_type_is_si(domain))
+ ret = intel_pasid_setup_pass_through(iommu, domain,
+ dev, PASID_RID2PASID);
+@@ -2627,7 +2627,7 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu,
+ else
+ ret = intel_pasid_setup_second_level(iommu, domain,
+ dev, PASID_RID2PASID);
+- spin_unlock(&iommu->lock);
++ spin_unlock_irqrestore(&iommu->lock, flags);
+ if (ret) {
+ dev_err(dev, "Setup RID2PASID failed\n");
+ dmar_remove_one_dev_info(dev);
+diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c
+index 4b1eb89b401d9..1ad518821157f 100644
+--- a/drivers/mmc/core/queue.c
++++ b/drivers/mmc/core/queue.c
+@@ -190,7 +190,7 @@ static void mmc_queue_setup_discard(struct request_queue *q,
+ q->limits.discard_granularity = card->pref_erase << 9;
+ /* granularity must not be greater than max. discard */
+ if (card->pref_erase > max_discard)
+- q->limits.discard_granularity = 0;
++ q->limits.discard_granularity = SECTOR_SIZE;
+ if (mmc_can_secure_erase_trim(card))
+ blk_queue_flag_set(QUEUE_FLAG_SECERASE, q);
+ }
+diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
+index 500aa3e19a4c7..fddf7c502355b 100644
+--- a/drivers/net/bonding/bond_main.c
++++ b/drivers/net/bonding/bond_main.c
+@@ -1195,6 +1195,7 @@ static void bond_setup_by_slave(struct net_device *bond_dev,
+
+ bond_dev->type = slave_dev->type;
+ bond_dev->hard_header_len = slave_dev->hard_header_len;
++ bond_dev->needed_headroom = slave_dev->needed_headroom;
+ bond_dev->addr_len = slave_dev->addr_len;
+
+ memcpy(bond_dev->broadcast, slave_dev->broadcast,
+diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
+index 7c167a394b762..259a612da0030 100644
+--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
++++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
+@@ -1105,8 +1105,21 @@ static int vsc9959_prevalidate_phy_mode(struct ocelot *ocelot, int port,
+ }
+ }
+
++/* Watermark encode
++ * Bit 8: Unit; 0:1, 1:16
++ * Bit 7-0: Value to be multiplied with unit
++ */
++static u16 vsc9959_wm_enc(u16 value)
++{
++ if (value >= BIT(8))
++ return BIT(8) | (value / 16);
++
++ return value;
++}
++
+ static const struct ocelot_ops vsc9959_ops = {
+ .reset = vsc9959_reset,
++ .wm_enc = vsc9959_wm_enc,
+ };
+
+ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
+@@ -1215,8 +1228,28 @@ static void vsc9959_mdio_bus_free(struct ocelot *ocelot)
+ static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port,
+ u32 speed)
+ {
++ u8 tas_speed;
++
++ switch (speed) {
++ case SPEED_10:
++ tas_speed = OCELOT_SPEED_10;
++ break;
++ case SPEED_100:
++ tas_speed = OCELOT_SPEED_100;
++ break;
++ case SPEED_1000:
++ tas_speed = OCELOT_SPEED_1000;
++ break;
++ case SPEED_2500:
++ tas_speed = OCELOT_SPEED_2500;
++ break;
++ default:
++ tas_speed = OCELOT_SPEED_1000;
++ break;
++ }
++
+ ocelot_rmw_rix(ocelot,
+- QSYS_TAG_CONFIG_LINK_SPEED(speed),
++ QSYS_TAG_CONFIG_LINK_SPEED(tas_speed),
+ QSYS_TAG_CONFIG_LINK_SPEED_M,
+ QSYS_TAG_CONFIG, port);
+ }
+diff --git a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c
+index cbaa1924afbe1..706e959bf02ac 100644
+--- a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c
++++ b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c
+@@ -1219,7 +1219,7 @@ static int octeon_mgmt_open(struct net_device *netdev)
+ */
+ if (netdev->phydev) {
+ netif_carrier_off(netdev);
+- phy_start_aneg(netdev->phydev);
++ phy_start(netdev->phydev);
+ }
+
+ netif_wake_queue(netdev);
+@@ -1247,8 +1247,10 @@ static int octeon_mgmt_stop(struct net_device *netdev)
+ napi_disable(&p->napi);
+ netif_stop_queue(netdev);
+
+- if (netdev->phydev)
++ if (netdev->phydev) {
++ phy_stop(netdev->phydev);
+ phy_disconnect(netdev->phydev);
++ }
+
+ netif_carrier_off(netdev);
+
+diff --git a/drivers/net/ethernet/huawei/hinic/Kconfig b/drivers/net/ethernet/huawei/hinic/Kconfig
+index 936e2dd3bb135..b47bd5440c5f0 100644
+--- a/drivers/net/ethernet/huawei/hinic/Kconfig
++++ b/drivers/net/ethernet/huawei/hinic/Kconfig
+@@ -6,6 +6,7 @@
+ config HINIC
+ tristate "Huawei Intelligent PCIE Network Interface Card"
+ depends on (PCI_MSI && (X86 || ARM64))
++ select NET_DEVLINK
+ help
+ This driver supports HiNIC PCIE Ethernet cards.
+ To compile this driver as part of the kernel, choose Y here.
+diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_api_cmd.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_api_cmd.c
+index 583fd24c29cf6..29e88e25a4a4f 100644
+--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_api_cmd.c
++++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_api_cmd.c
+@@ -112,6 +112,26 @@ static u32 get_hw_cons_idx(struct hinic_api_cmd_chain *chain)
+ return HINIC_API_CMD_STATUS_GET(val, CONS_IDX);
+ }
+
++static void dump_api_chain_reg(struct hinic_api_cmd_chain *chain)
++{
++ u32 addr, val;
++
++ addr = HINIC_CSR_API_CMD_STATUS_ADDR(chain->chain_type);
++ val = hinic_hwif_read_reg(chain->hwif, addr);
++
++ dev_err(&chain->hwif->pdev->dev, "Chain type: 0x%x, cpld error: 0x%x, check error: 0x%x, current fsm: 0x%x\n",
++ chain->chain_type, HINIC_API_CMD_STATUS_GET(val, CPLD_ERR),
++ HINIC_API_CMD_STATUS_GET(val, CHKSUM_ERR),
++ HINIC_API_CMD_STATUS_GET(val, FSM));
++
++ dev_err(&chain->hwif->pdev->dev, "Chain hw current ci: 0x%x\n",
++ HINIC_API_CMD_STATUS_GET(val, CONS_IDX));
++
++ addr = HINIC_CSR_API_CMD_CHAIN_PI_ADDR(chain->chain_type);
++ val = hinic_hwif_read_reg(chain->hwif, addr);
++ dev_err(&chain->hwif->pdev->dev, "Chain hw current pi: 0x%x\n", val);
++}
++
+ /**
+ * chain_busy - check if the chain is still processing last requests
+ * @chain: chain to check
+@@ -131,8 +151,10 @@ static int chain_busy(struct hinic_api_cmd_chain *chain)
+
+ /* check for a space for a new command */
+ if (chain->cons_idx == MASKED_IDX(chain, prod_idx + 1)) {
+- dev_err(&pdev->dev, "API CMD chain %d is busy\n",
+- chain->chain_type);
++ dev_err(&pdev->dev, "API CMD chain %d is busy, cons_idx: %d, prod_idx: %d\n",
++ chain->chain_type, chain->cons_idx,
++ chain->prod_idx);
++ dump_api_chain_reg(chain);
+ return -EBUSY;
+ }
+ break;
+@@ -332,6 +354,7 @@ static int wait_for_api_cmd_completion(struct hinic_api_cmd_chain *chain)
+ err = wait_for_status_poll(chain);
+ if (err) {
+ dev_err(&pdev->dev, "API CMD Poll status timeout\n");
++ dump_api_chain_reg(chain);
+ break;
+ }
+ break;
+diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_api_cmd.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_api_cmd.h
+index 0ba00fd828dfc..6d1654b050ad5 100644
+--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_api_cmd.h
++++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_api_cmd.h
+@@ -103,10 +103,14 @@
+ HINIC_API_CMD_STATUS_HEADER_##member##_MASK)
+
+ #define HINIC_API_CMD_STATUS_CONS_IDX_SHIFT 0
++#define HINIC_API_CMD_STATUS_FSM_SHIFT 24
+ #define HINIC_API_CMD_STATUS_CHKSUM_ERR_SHIFT 28
++#define HINIC_API_CMD_STATUS_CPLD_ERR_SHIFT 30
+
+ #define HINIC_API_CMD_STATUS_CONS_IDX_MASK 0xFFFFFF
++#define HINIC_API_CMD_STATUS_FSM_MASK 0xFU
+ #define HINIC_API_CMD_STATUS_CHKSUM_ERR_MASK 0x3
++#define HINIC_API_CMD_STATUS_CPLD_ERR_MASK 0x1U
+
+ #define HINIC_API_CMD_STATUS_GET(val, member) \
+ (((val) >> HINIC_API_CMD_STATUS_##member##_SHIFT) & \
+diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c
+index cb5b6e5f787f2..e0eb294779ec1 100644
+--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c
++++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c
+@@ -401,6 +401,7 @@ static int cmdq_sync_cmd_direct_resp(struct hinic_cmdq *cmdq,
+
+ spin_unlock_bh(&cmdq->cmdq_lock);
+
++ hinic_dump_ceq_info(cmdq->hwdev);
+ return -ETIMEDOUT;
+ }
+
+@@ -807,6 +808,7 @@ static int init_cmdqs_ctxt(struct hinic_hwdev *hwdev,
+
+ cmdq_type = HINIC_CMDQ_SYNC;
+ for (; cmdq_type < HINIC_MAX_CMDQ_TYPES; cmdq_type++) {
++ cmdqs->cmdq[cmdq_type].hwdev = hwdev;
+ err = init_cmdq(&cmdqs->cmdq[cmdq_type],
+ &cmdqs->saved_wqs[cmdq_type], cmdq_type,
+ db_area[cmdq_type]);
+diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.h
+index 3e4b0aef9fe6c..f40c31e1879f1 100644
+--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.h
++++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.h
+@@ -130,6 +130,8 @@ struct hinic_cmdq_ctxt {
+ };
+
+ struct hinic_cmdq {
++ struct hinic_hwdev *hwdev;
++
+ struct hinic_wq *wq;
+
+ enum hinic_cmdq_type cmdq_type;
+diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
+index b735bc537508f..298ceb930cc62 100644
+--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
++++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
+@@ -253,9 +253,9 @@ static int init_fw_ctxt(struct hinic_hwdev *hwdev)
+ &fw_ctxt, sizeof(fw_ctxt),
+ &fw_ctxt, &out_size);
+ if (err || (out_size != sizeof(fw_ctxt)) || fw_ctxt.status) {
+- dev_err(&pdev->dev, "Failed to init FW ctxt, ret = %d\n",
+- fw_ctxt.status);
+- return -EFAULT;
++ dev_err(&pdev->dev, "Failed to init FW ctxt, err: %d, status: 0x%x, out size: 0x%x\n",
++ err, fw_ctxt.status, out_size);
++ return -EIO;
+ }
+
+ return 0;
+@@ -420,9 +420,9 @@ static int get_base_qpn(struct hinic_hwdev *hwdev, u16 *base_qpn)
+ &cmd_base_qpn, sizeof(cmd_base_qpn),
+ &cmd_base_qpn, &out_size);
+ if (err || (out_size != sizeof(cmd_base_qpn)) || cmd_base_qpn.status) {
+- dev_err(&pdev->dev, "Failed to get base qpn, status = %d\n",
+- cmd_base_qpn.status);
+- return -EFAULT;
++ dev_err(&pdev->dev, "Failed to get base qpn, err: %d, status: 0x%x, out size: 0x%x\n",
++ err, cmd_base_qpn.status, out_size);
++ return -EIO;
+ }
+
+ *base_qpn = cmd_base_qpn.qpn;
+diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c
+index 397936cac304c..ca8cb68a8d206 100644
+--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c
++++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c
+@@ -953,3 +953,42 @@ void hinic_ceqs_free(struct hinic_ceqs *ceqs)
+ for (q_id = 0; q_id < ceqs->num_ceqs; q_id++)
+ remove_eq(&ceqs->ceq[q_id]);
+ }
++
++void hinic_dump_ceq_info(struct hinic_hwdev *hwdev)
++{
++ struct hinic_eq *eq = NULL;
++ u32 addr, ci, pi;
++ int q_id;
++
++ for (q_id = 0; q_id < hwdev->func_to_io.ceqs.num_ceqs; q_id++) {
++ eq = &hwdev->func_to_io.ceqs.ceq[q_id];
++ addr = EQ_CONS_IDX_REG_ADDR(eq);
++ ci = hinic_hwif_read_reg(hwdev->hwif, addr);
++ addr = EQ_PROD_IDX_REG_ADDR(eq);
++ pi = hinic_hwif_read_reg(hwdev->hwif, addr);
++ dev_err(&hwdev->hwif->pdev->dev, "Ceq id: %d, ci: 0x%08x, sw_ci: 0x%08x, pi: 0x%x, tasklet_state: 0x%lx, wrap: %d, ceqe: 0x%x\n",
++ q_id, ci, eq->cons_idx, pi,
++ eq->ceq_tasklet.state,
++ eq->wrapped, be32_to_cpu(*(__be32 *)(GET_CURR_CEQ_ELEM(eq))));
++ }
++}
++
++void hinic_dump_aeq_info(struct hinic_hwdev *hwdev)
++{
++ struct hinic_aeq_elem *aeqe_pos = NULL;
++ struct hinic_eq *eq = NULL;
++ u32 addr, ci, pi;
++ int q_id;
++
++ for (q_id = 0; q_id < hwdev->aeqs.num_aeqs; q_id++) {
++ eq = &hwdev->aeqs.aeq[q_id];
++ addr = EQ_CONS_IDX_REG_ADDR(eq);
++ ci = hinic_hwif_read_reg(hwdev->hwif, addr);
++ addr = EQ_PROD_IDX_REG_ADDR(eq);
++ pi = hinic_hwif_read_reg(hwdev->hwif, addr);
++ aeqe_pos = GET_CURR_AEQ_ELEM(eq);
++ dev_err(&hwdev->hwif->pdev->dev, "Aeq id: %d, ci: 0x%08x, pi: 0x%x, work_state: 0x%x, wrap: %d, desc: 0x%x\n",
++ q_id, ci, pi, work_busy(&eq->aeq_work.work),
++ eq->wrapped, be32_to_cpu(aeqe_pos->desc));
++ }
++}
+diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.h
+index 74b9ff90640c2..43065fc708693 100644
+--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.h
++++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.h
+@@ -162,7 +162,7 @@ enum hinic_eqe_state {
+
+ struct hinic_aeq_elem {
+ u8 data[HINIC_AEQE_DATA_SIZE];
+- u32 desc;
++ __be32 desc;
+ };
+
+ struct hinic_eq_work {
+@@ -254,4 +254,8 @@ int hinic_ceqs_init(struct hinic_ceqs *ceqs, struct hinic_hwif *hwif,
+
+ void hinic_ceqs_free(struct hinic_ceqs *ceqs);
+
++void hinic_dump_ceq_info(struct hinic_hwdev *hwdev);
++
++void hinic_dump_aeq_info(struct hinic_hwdev *hwdev);
++
+ #endif
+diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_if.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_if.c
+index cf127d896ba69..bc8925c0c982c 100644
+--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_if.c
++++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_if.c
+@@ -21,6 +21,8 @@
+
+ #define WAIT_HWIF_READY_TIMEOUT 10000
+
++#define HINIC_SELFTEST_RESULT 0x883C
++
+ /**
+ * hinic_msix_attr_set - set message attribute for msix entry
+ * @hwif: the HW interface of a pci function device
+@@ -369,6 +371,26 @@ u16 hinic_pf_id_of_vf_hw(struct hinic_hwif *hwif)
+ return HINIC_FA0_GET(attr0, PF_IDX);
+ }
+
++static void __print_selftest_reg(struct hinic_hwif *hwif)
++{
++ u32 addr, attr0, attr1;
++
++ addr = HINIC_CSR_FUNC_ATTR1_ADDR;
++ attr1 = hinic_hwif_read_reg(hwif, addr);
++
++ if (attr1 == HINIC_PCIE_LINK_DOWN) {
++ dev_err(&hwif->pdev->dev, "PCIE is link down\n");
++ return;
++ }
++
++ addr = HINIC_CSR_FUNC_ATTR0_ADDR;
++ attr0 = hinic_hwif_read_reg(hwif, addr);
++ if (HINIC_FA0_GET(attr0, FUNC_TYPE) != HINIC_VF &&
++ !HINIC_FA0_GET(attr0, PCI_INTF_IDX))
++ dev_err(&hwif->pdev->dev, "Selftest reg: 0x%08x\n",
++ hinic_hwif_read_reg(hwif, HINIC_SELFTEST_RESULT));
++}
++
+ /**
+ * hinic_init_hwif - initialize the hw interface
+ * @hwif: the HW interface of a pci function device
+@@ -398,6 +420,7 @@ int hinic_init_hwif(struct hinic_hwif *hwif, struct pci_dev *pdev)
+ err = wait_hwif_ready(hwif);
+ if (err) {
+ dev_err(&pdev->dev, "HW interface is not ready\n");
++ __print_selftest_reg(hwif);
+ goto err_hwif_ready;
+ }
+
+diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_if.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_if.h
+index 0872e035faa11..c06f2253151e2 100644
+--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_if.h
++++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_if.h
+@@ -12,6 +12,8 @@
+ #include <linux/types.h>
+ #include <asm/byteorder.h>
+
++#define HINIC_PCIE_LINK_DOWN 0xFFFFFFFF
++
+ #define HINIC_DMA_ATTR_ST_SHIFT 0
+ #define HINIC_DMA_ATTR_AT_SHIFT 8
+ #define HINIC_DMA_ATTR_PH_SHIFT 10
+@@ -249,13 +251,17 @@ struct hinic_hwif {
+
+ static inline u32 hinic_hwif_read_reg(struct hinic_hwif *hwif, u32 reg)
+ {
+- return be32_to_cpu(readl(hwif->cfg_regs_bar + reg));
++ u32 out = readl(hwif->cfg_regs_bar + reg);
++
++ return be32_to_cpu(*(__be32 *)&out);
+ }
+
+ static inline void hinic_hwif_write_reg(struct hinic_hwif *hwif, u32 reg,
+ u32 val)
+ {
+- writel(cpu_to_be32(val), hwif->cfg_regs_bar + reg);
++ __be32 in = cpu_to_be32(val);
++
++ writel(*(u32 *)&in, hwif->cfg_regs_bar + reg);
+ }
+
+ int hinic_msix_attr_set(struct hinic_hwif *hwif, u16 msix_index,
+diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_mbox.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_mbox.c
+index bc2f87e6cb5d7..47c93f946b94d 100644
+--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_mbox.c
++++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_mbox.c
+@@ -650,6 +650,7 @@ wait_for_mbox_seg_completion(struct hinic_mbox_func_to_func *func_to_func,
+ if (!wait_for_completion_timeout(done, jif)) {
+ dev_err(&hwdev->hwif->pdev->dev, "Send mailbox segment timeout\n");
+ dump_mox_reg(hwdev);
++ hinic_dump_aeq_info(hwdev);
+ return -ETIMEDOUT;
+ }
+
+@@ -897,6 +898,7 @@ int hinic_mbox_to_func(struct hinic_mbox_func_to_func *func_to_func,
+ set_mbox_to_func_event(func_to_func, EVENT_TIMEOUT);
+ dev_err(&func_to_func->hwif->pdev->dev,
+ "Send mbox msg timeout, msg_id: %d\n", msg_info.msg_id);
++ hinic_dump_aeq_info(func_to_func->hwdev);
+ err = -ETIMEDOUT;
+ goto err_send_mbox;
+ }
+diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c
+index 7fe39a155b329..070288c8b4f37 100644
+--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c
++++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c
+@@ -276,6 +276,7 @@ static int msg_to_mgmt_sync(struct hinic_pf_to_mgmt *pf_to_mgmt,
+
+ if (!wait_for_completion_timeout(recv_done, timeo)) {
+ dev_err(&pdev->dev, "MGMT timeout, MSG id = %d\n", msg_id);
++ hinic_dump_aeq_info(pf_to_mgmt->hwdev);
+ err = -ETIMEDOUT;
+ goto unlock_sync_msg;
+ }
+diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port.c b/drivers/net/ethernet/huawei/hinic/hinic_port.c
+index 175c0ee000384..2be7c254cca90 100644
+--- a/drivers/net/ethernet/huawei/hinic/hinic_port.c
++++ b/drivers/net/ethernet/huawei/hinic/hinic_port.c
+@@ -58,11 +58,11 @@ static int change_mac(struct hinic_dev *nic_dev, const u8 *addr,
+ sizeof(port_mac_cmd),
+ &port_mac_cmd, &out_size);
+ if (err || out_size != sizeof(port_mac_cmd) ||
+- (port_mac_cmd.status &&
+- port_mac_cmd.status != HINIC_PF_SET_VF_ALREADY &&
+- port_mac_cmd.status != HINIC_MGMT_STATUS_EXIST)) {
+- dev_err(&pdev->dev, "Failed to change MAC, ret = %d\n",
+- port_mac_cmd.status);
++ (port_mac_cmd.status &&
++ (port_mac_cmd.status != HINIC_PF_SET_VF_ALREADY || !HINIC_IS_VF(hwif)) &&
++ port_mac_cmd.status != HINIC_MGMT_STATUS_EXIST)) {
++ dev_err(&pdev->dev, "Failed to change MAC, err: %d, status: 0x%x, out size: 0x%x\n",
++ err, port_mac_cmd.status, out_size);
+ return -EFAULT;
+ }
+
+@@ -129,8 +129,8 @@ int hinic_port_get_mac(struct hinic_dev *nic_dev, u8 *addr)
+ &port_mac_cmd, sizeof(port_mac_cmd),
+ &port_mac_cmd, &out_size);
+ if (err || (out_size != sizeof(port_mac_cmd)) || port_mac_cmd.status) {
+- dev_err(&pdev->dev, "Failed to get mac, ret = %d\n",
+- port_mac_cmd.status);
++ dev_err(&pdev->dev, "Failed to get mac, err: %d, status: 0x%x, out size: 0x%x\n",
++ err, port_mac_cmd.status, out_size);
+ return -EFAULT;
+ }
+
+@@ -172,9 +172,9 @@ int hinic_port_set_mtu(struct hinic_dev *nic_dev, int new_mtu)
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_CHANGE_MTU,
+ &port_mtu_cmd, sizeof(port_mtu_cmd),
+ &port_mtu_cmd, &out_size);
+- if (err || (out_size != sizeof(port_mtu_cmd)) || port_mtu_cmd.status) {
+- dev_err(&pdev->dev, "Failed to set mtu, ret = %d\n",
+- port_mtu_cmd.status);
++ if (err || out_size != sizeof(port_mtu_cmd) || port_mtu_cmd.status) {
++ dev_err(&pdev->dev, "Failed to set mtu, err: %d, status: 0x%x, out size: 0x%x\n",
++ err, port_mtu_cmd.status, out_size);
+ return -EFAULT;
+ }
+
+@@ -264,8 +264,8 @@ int hinic_port_link_state(struct hinic_dev *nic_dev,
+ &link_cmd, sizeof(link_cmd),
+ &link_cmd, &out_size);
+ if (err || (out_size != sizeof(link_cmd)) || link_cmd.status) {
+- dev_err(&pdev->dev, "Failed to get link state, ret = %d\n",
+- link_cmd.status);
++ dev_err(&pdev->dev, "Failed to get link state, err: %d, status: 0x%x, out size: 0x%x\n",
++ err, link_cmd.status, out_size);
+ return -EINVAL;
+ }
+
+@@ -298,8 +298,8 @@ int hinic_port_set_state(struct hinic_dev *nic_dev, enum hinic_port_state state)
+ &port_state, sizeof(port_state),
+ &port_state, &out_size);
+ if (err || (out_size != sizeof(port_state)) || port_state.status) {
+- dev_err(&pdev->dev, "Failed to set port state, ret = %d\n",
+- port_state.status);
++ dev_err(&pdev->dev, "Failed to set port state, err: %d, status: 0x%x, out size: 0x%x\n",
++ err, port_state.status, out_size);
+ return -EFAULT;
+ }
+
+@@ -330,8 +330,8 @@ int hinic_port_set_func_state(struct hinic_dev *nic_dev,
+ &func_state, sizeof(func_state),
+ &func_state, &out_size);
+ if (err || (out_size != sizeof(func_state)) || func_state.status) {
+- dev_err(&pdev->dev, "Failed to set port func state, ret = %d\n",
+- func_state.status);
++ dev_err(&pdev->dev, "Failed to set port func state, err: %d, status: 0x%x, out size: 0x%x\n",
++ err, func_state.status, out_size);
+ return -EFAULT;
+ }
+
+@@ -361,9 +361,9 @@ int hinic_port_get_cap(struct hinic_dev *nic_dev,
+ port_cap, &out_size);
+ if (err || (out_size != sizeof(*port_cap)) || port_cap->status) {
+ dev_err(&pdev->dev,
+- "Failed to get port capabilities, ret = %d\n",
+- port_cap->status);
+- return -EINVAL;
++ "Failed to get port capabilities, err: %d, status: 0x%x, out size: 0x%x\n",
++ err, port_cap->status, out_size);
++ return -EIO;
+ }
+
+ return 0;
+@@ -393,9 +393,9 @@ int hinic_port_set_tso(struct hinic_dev *nic_dev, enum hinic_tso_state state)
+ &tso_cfg, &out_size);
+ if (err || out_size != sizeof(tso_cfg) || tso_cfg.status) {
+ dev_err(&pdev->dev,
+- "Failed to set port tso, ret = %d\n",
+- tso_cfg.status);
+- return -EINVAL;
++ "Failed to set port tso, err: %d, status: 0x%x, out size: 0x%x\n",
++ err, tso_cfg.status, out_size);
++ return -EIO;
+ }
+
+ return 0;
+@@ -423,9 +423,9 @@ int hinic_set_rx_csum_offload(struct hinic_dev *nic_dev, u32 en)
+ &rx_csum_cfg, &out_size);
+ if (err || !out_size || rx_csum_cfg.status) {
+ dev_err(&pdev->dev,
+- "Failed to set rx csum offload, ret = %d\n",
+- rx_csum_cfg.status);
+- return -EINVAL;
++ "Failed to set rx csum offload, err: %d, status: 0x%x, out size: 0x%x\n",
++ err, rx_csum_cfg.status, out_size);
++ return -EIO;
+ }
+
+ return 0;
+@@ -480,9 +480,9 @@ int hinic_set_max_qnum(struct hinic_dev *nic_dev, u8 num_rqs)
+ &rq_num, &out_size);
+ if (err || !out_size || rq_num.status) {
+ dev_err(&pdev->dev,
+- "Failed to rxq number, ret = %d\n",
+- rq_num.status);
+- return -EINVAL;
++ "Failed to set rxq number, err: %d, status: 0x%x, out size: 0x%x\n",
++ err, rq_num.status, out_size);
++ return -EIO;
+ }
+
+ return 0;
+@@ -508,9 +508,9 @@ static int hinic_set_rx_lro(struct hinic_dev *nic_dev, u8 ipv4_en, u8 ipv6_en,
+ &lro_cfg, &out_size);
+ if (err || !out_size || lro_cfg.status) {
+ dev_err(&pdev->dev,
+- "Failed to set lro offload, ret = %d\n",
+- lro_cfg.status);
+- return -EINVAL;
++ "Failed to set lro offload, err: %d, status: 0x%x, out size: 0x%x\n",
++ err, lro_cfg.status, out_size);
++ return -EIO;
+ }
+
+ return 0;
+@@ -542,10 +542,10 @@ static int hinic_set_rx_lro_timer(struct hinic_dev *nic_dev, u32 timer_value)
+
+ if (err || !out_size || lro_timer.status) {
+ dev_err(&pdev->dev,
+- "Failed to set lro timer, ret = %d\n",
+- lro_timer.status);
++ "Failed to set lro timer, err: %d, status: 0x%x, out size: 0x%x\n",
++ err, lro_timer.status, out_size);
+
+- return -EINVAL;
++ return -EIO;
+ }
+
+ return 0;
+diff --git a/drivers/net/ethernet/huawei/hinic/hinic_sriov.c b/drivers/net/ethernet/huawei/hinic/hinic_sriov.c
+index efab2dd2c889b..b757f7057b8fe 100644
+--- a/drivers/net/ethernet/huawei/hinic/hinic_sriov.c
++++ b/drivers/net/ethernet/huawei/hinic/hinic_sriov.c
+@@ -38,11 +38,10 @@ static int hinic_set_mac(struct hinic_hwdev *hwdev, const u8 *mac_addr,
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_MAC, &mac_info,
+ sizeof(mac_info), &mac_info, &out_size);
+ if (err || out_size != sizeof(mac_info) ||
+- (mac_info.status && mac_info.status != HINIC_PF_SET_VF_ALREADY &&
+- mac_info.status != HINIC_MGMT_STATUS_EXIST)) {
+- dev_err(&hwdev->func_to_io.hwif->pdev->dev, "Failed to change MAC, ret = %d\n",
+- mac_info.status);
+- return -EFAULT;
++ (mac_info.status && mac_info.status != HINIC_MGMT_STATUS_EXIST)) {
++ dev_err(&hwdev->func_to_io.hwif->pdev->dev, "Failed to set MAC, err: %d, status: 0x%x, out size: 0x%x\n",
++ err, mac_info.status, out_size);
++ return -EIO;
+ }
+
+ return 0;
+@@ -452,8 +451,7 @@ struct hinic_sriov_info *hinic_get_sriov_info_by_pcidev(struct pci_dev *pdev)
+
+ static int hinic_check_mac_info(u8 status, u16 vlan_id)
+ {
+- if ((status && status != HINIC_MGMT_STATUS_EXIST &&
+- status != HINIC_PF_SET_VF_ALREADY) ||
++ if ((status && status != HINIC_MGMT_STATUS_EXIST) ||
+ (vlan_id & CHECK_IPSU_15BIT &&
+ status == HINIC_MGMT_STATUS_EXIST))
+ return -EINVAL;
+@@ -495,12 +493,6 @@ static int hinic_update_mac(struct hinic_hwdev *hwdev, u8 *old_mac,
+ return -EINVAL;
+ }
+
+- if (mac_info.status == HINIC_PF_SET_VF_ALREADY) {
+- dev_warn(&hwdev->hwif->pdev->dev,
+- "PF has already set VF MAC. Ignore update operation\n");
+- return HINIC_PF_SET_VF_ALREADY;
+- }
+-
+ if (mac_info.status == HINIC_MGMT_STATUS_EXIST)
+ dev_warn(&hwdev->hwif->pdev->dev, "MAC is repeated. Ignore update operation\n");
+
+diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
+index d338efe5f3f55..91343e2d3a145 100644
+--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
++++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
+@@ -3777,7 +3777,6 @@ err_dma:
+ return err;
+ }
+
+-#ifdef CONFIG_PM
+ /**
+ * iavf_suspend - Power management suspend routine
+ * @pdev: PCI device information struct
+@@ -3785,11 +3784,10 @@ err_dma:
+ *
+ * Called when the system (VM) is entering sleep/suspend.
+ **/
+-static int iavf_suspend(struct pci_dev *pdev, pm_message_t state)
++static int __maybe_unused iavf_suspend(struct device *dev_d)
+ {
+- struct net_device *netdev = pci_get_drvdata(pdev);
++ struct net_device *netdev = dev_get_drvdata(dev_d);
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+- int retval = 0;
+
+ netif_device_detach(netdev);
+
+@@ -3807,12 +3805,6 @@ static int iavf_suspend(struct pci_dev *pdev, pm_message_t state)
+
+ clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
+
+- retval = pci_save_state(pdev);
+- if (retval)
+- return retval;
+-
+- pci_disable_device(pdev);
+-
+ return 0;
+ }
+
+@@ -3822,24 +3814,13 @@ static int iavf_suspend(struct pci_dev *pdev, pm_message_t state)
+ *
+ * Called when the system (VM) is resumed from sleep/suspend.
+ **/
+-static int iavf_resume(struct pci_dev *pdev)
++static int __maybe_unused iavf_resume(struct device *dev_d)
+ {
+- struct iavf_adapter *adapter = pci_get_drvdata(pdev);
+- struct net_device *netdev = adapter->netdev;
++ struct pci_dev *pdev = to_pci_dev(dev_d);
++ struct net_device *netdev = pci_get_drvdata(pdev);
++ struct iavf_adapter *adapter = netdev_priv(netdev);
+ u32 err;
+
+- pci_set_power_state(pdev, PCI_D0);
+- pci_restore_state(pdev);
+- /* pci_restore_state clears dev->state_saved so call
+- * pci_save_state to restore it.
+- */
+- pci_save_state(pdev);
+-
+- err = pci_enable_device_mem(pdev);
+- if (err) {
+- dev_err(&pdev->dev, "Cannot enable PCI device from suspend.\n");
+- return err;
+- }
+ pci_set_master(pdev);
+
+ rtnl_lock();
+@@ -3863,7 +3844,6 @@ static int iavf_resume(struct pci_dev *pdev)
+ return err;
+ }
+
+-#endif /* CONFIG_PM */
+ /**
+ * iavf_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+@@ -3965,16 +3945,15 @@ static void iavf_remove(struct pci_dev *pdev)
+ pci_disable_device(pdev);
+ }
+
++static SIMPLE_DEV_PM_OPS(iavf_pm_ops, iavf_suspend, iavf_resume);
++
+ static struct pci_driver iavf_driver = {
+- .name = iavf_driver_name,
+- .id_table = iavf_pci_tbl,
+- .probe = iavf_probe,
+- .remove = iavf_remove,
+-#ifdef CONFIG_PM
+- .suspend = iavf_suspend,
+- .resume = iavf_resume,
+-#endif
+- .shutdown = iavf_shutdown,
++ .name = iavf_driver_name,
++ .id_table = iavf_pci_tbl,
++ .probe = iavf_probe,
++ .remove = iavf_remove,
++ .driver.pm = &iavf_pm_ops,
++ .shutdown = iavf_shutdown,
+ };
+
+ /**
+diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
+index 2e3a39cea2c03..4c5845a0965a9 100644
+--- a/drivers/net/ethernet/intel/ice/ice_lib.c
++++ b/drivers/net/ethernet/intel/ice/ice_lib.c
+@@ -240,7 +240,7 @@ static int ice_get_free_slot(void *array, int size, int curr)
+ * ice_vsi_delete - delete a VSI from the switch
+ * @vsi: pointer to VSI being removed
+ */
+-void ice_vsi_delete(struct ice_vsi *vsi)
++static void ice_vsi_delete(struct ice_vsi *vsi)
+ {
+ struct ice_pf *pf = vsi->back;
+ struct ice_vsi_ctx *ctxt;
+@@ -307,7 +307,7 @@ static void ice_vsi_free_arrays(struct ice_vsi *vsi)
+ *
+ * Returns 0 on success, negative on failure
+ */
+-int ice_vsi_clear(struct ice_vsi *vsi)
++static int ice_vsi_clear(struct ice_vsi *vsi)
+ {
+ struct ice_pf *pf = NULL;
+ struct device *dev;
+@@ -557,7 +557,7 @@ static int ice_vsi_get_qs(struct ice_vsi *vsi)
+ * ice_vsi_put_qs - Release queues from VSI to PF
+ * @vsi: the VSI that is going to release queues
+ */
+-void ice_vsi_put_qs(struct ice_vsi *vsi)
++static void ice_vsi_put_qs(struct ice_vsi *vsi)
+ {
+ struct ice_pf *pf = vsi->back;
+ int i;
+@@ -1190,6 +1190,18 @@ static void ice_vsi_clear_rings(struct ice_vsi *vsi)
+ {
+ int i;
+
++ /* Avoid stale references by clearing map from vector to ring */
++ if (vsi->q_vectors) {
++ ice_for_each_q_vector(vsi, i) {
++ struct ice_q_vector *q_vector = vsi->q_vectors[i];
++
++ if (q_vector) {
++ q_vector->tx.ring = NULL;
++ q_vector->rx.ring = NULL;
++ }
++ }
++ }
++
+ if (vsi->tx_rings) {
+ for (i = 0; i < vsi->alloc_txq; i++) {
+ if (vsi->tx_rings[i]) {
+@@ -2254,7 +2266,7 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
+ if (status) {
+ dev_err(dev, "VSI %d failed lan queue config, error %s\n",
+ vsi->vsi_num, ice_stat_str(status));
+- goto unroll_vector_base;
++ goto unroll_clear_rings;
+ }
+
+ /* Add switch rule to drop all Tx Flow Control Frames, of look up
+diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h
+index d80e6afa45112..2954b30e6ec79 100644
+--- a/drivers/net/ethernet/intel/ice/ice_lib.h
++++ b/drivers/net/ethernet/intel/ice/ice_lib.h
+@@ -43,10 +43,6 @@ int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc);
+
+ void ice_cfg_sw_lldp(struct ice_vsi *vsi, bool tx, bool create);
+
+-void ice_vsi_delete(struct ice_vsi *vsi);
+-
+-int ice_vsi_clear(struct ice_vsi *vsi);
+-
+ #ifdef CONFIG_DCB
+ int ice_vsi_cfg_tc(struct ice_vsi *vsi, u8 ena_tc);
+ #endif /* CONFIG_DCB */
+@@ -77,8 +73,6 @@ bool ice_is_reset_in_progress(unsigned long *state);
+ void
+ ice_write_qrxflxp_cntxt(struct ice_hw *hw, u16 pf_q, u32 rxdid, u32 prio);
+
+-void ice_vsi_put_qs(struct ice_vsi *vsi);
+-
+ void ice_vsi_dis_irq(struct ice_vsi *vsi);
+
+ void ice_vsi_free_irq(struct ice_vsi *vsi);
+diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
+index 4cbd49c87568a..4b52f1dea7f3a 100644
+--- a/drivers/net/ethernet/intel/ice/ice_main.c
++++ b/drivers/net/ethernet/intel/ice/ice_main.c
+@@ -2605,10 +2605,8 @@ static int ice_setup_pf_sw(struct ice_pf *pf)
+ return -EBUSY;
+
+ vsi = ice_pf_vsi_setup(pf, pf->hw.port_info);
+- if (!vsi) {
+- status = -ENOMEM;
+- goto unroll_vsi_setup;
+- }
++ if (!vsi)
++ return -ENOMEM;
+
+ status = ice_cfg_netdev(vsi);
+ if (status) {
+@@ -2655,12 +2653,7 @@ unroll_napi_add:
+ }
+
+ unroll_vsi_setup:
+- if (vsi) {
+- ice_vsi_free_q_vectors(vsi);
+- ice_vsi_delete(vsi);
+- ice_vsi_put_qs(vsi);
+- ice_vsi_clear(vsi);
+- }
++ ice_vsi_release(vsi);
+ return status;
+ }
+
+diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
+index 7d5d9d34f4e47..69a234e83b8b7 100644
+--- a/drivers/net/ethernet/marvell/mvneta.c
++++ b/drivers/net/ethernet/marvell/mvneta.c
+@@ -3372,24 +3372,15 @@ static int mvneta_txq_sw_init(struct mvneta_port *pp,
+ txq->last_desc = txq->size - 1;
+
+ txq->buf = kmalloc_array(txq->size, sizeof(*txq->buf), GFP_KERNEL);
+- if (!txq->buf) {
+- dma_free_coherent(pp->dev->dev.parent,
+- txq->size * MVNETA_DESC_ALIGNED_SIZE,
+- txq->descs, txq->descs_phys);
++ if (!txq->buf)
+ return -ENOMEM;
+- }
+
+ /* Allocate DMA buffers for TSO MAC/IP/TCP headers */
+ txq->tso_hdrs = dma_alloc_coherent(pp->dev->dev.parent,
+ txq->size * TSO_HEADER_SIZE,
+ &txq->tso_hdrs_phys, GFP_KERNEL);
+- if (!txq->tso_hdrs) {
+- kfree(txq->buf);
+- dma_free_coherent(pp->dev->dev.parent,
+- txq->size * MVNETA_DESC_ALIGNED_SIZE,
+- txq->descs, txq->descs_phys);
++ if (!txq->tso_hdrs)
+ return -ENOMEM;
+- }
+
+ /* Setup XPS mapping */
+ if (txq_number > 1)
+diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.c b/drivers/net/ethernet/marvell/octeontx2/af/mbox.c
+index 387e33fa417aa..2718fe201c147 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.c
++++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.c
+@@ -17,7 +17,7 @@
+
+ static const u16 msgs_offset = ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
+
+-void otx2_mbox_reset(struct otx2_mbox *mbox, int devid)
++void __otx2_mbox_reset(struct otx2_mbox *mbox, int devid)
+ {
+ void *hw_mbase = mbox->hwbase + (devid * MBOX_SIZE);
+ struct otx2_mbox_dev *mdev = &mbox->dev[devid];
+@@ -26,13 +26,21 @@ void otx2_mbox_reset(struct otx2_mbox *mbox, int devid)
+ tx_hdr = hw_mbase + mbox->tx_start;
+ rx_hdr = hw_mbase + mbox->rx_start;
+
+- spin_lock(&mdev->mbox_lock);
+ mdev->msg_size = 0;
+ mdev->rsp_size = 0;
+ tx_hdr->num_msgs = 0;
+ tx_hdr->msg_size = 0;
+ rx_hdr->num_msgs = 0;
+ rx_hdr->msg_size = 0;
++}
++EXPORT_SYMBOL(__otx2_mbox_reset);
++
++void otx2_mbox_reset(struct otx2_mbox *mbox, int devid)
++{
++ struct otx2_mbox_dev *mdev = &mbox->dev[devid];
++
++ spin_lock(&mdev->mbox_lock);
++ __otx2_mbox_reset(mbox, devid);
+ spin_unlock(&mdev->mbox_lock);
+ }
+ EXPORT_SYMBOL(otx2_mbox_reset);
+diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+index 6dfd0f90cd704..ab433789d2c31 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
++++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+@@ -93,6 +93,7 @@ struct mbox_msghdr {
+ };
+
+ void otx2_mbox_reset(struct otx2_mbox *mbox, int devid);
++void __otx2_mbox_reset(struct otx2_mbox *mbox, int devid);
+ void otx2_mbox_destroy(struct otx2_mbox *mbox);
+ int otx2_mbox_init(struct otx2_mbox *mbox, void __force *hwbase,
+ struct pci_dev *pdev, void __force *reg_base,
+diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+index dcf25a0920084..b89dde2c8b089 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+@@ -463,6 +463,7 @@ void rvu_nix_freemem(struct rvu *rvu);
+ int rvu_get_nixlf_count(struct rvu *rvu);
+ void rvu_nix_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int npalf);
+ int nix_get_nixlf(struct rvu *rvu, u16 pcifunc, int *nixlf, int *nix_blkaddr);
++int nix_update_bcast_mce_list(struct rvu *rvu, u16 pcifunc, bool add);
+
+ /* NPC APIs */
+ int rvu_npc_init(struct rvu *rvu);
+@@ -477,7 +478,7 @@ void rvu_npc_disable_promisc_entry(struct rvu *rvu, u16 pcifunc, int nixlf);
+ void rvu_npc_enable_promisc_entry(struct rvu *rvu, u16 pcifunc, int nixlf);
+ void rvu_npc_install_bcast_match_entry(struct rvu *rvu, u16 pcifunc,
+ int nixlf, u64 chan);
+-void rvu_npc_disable_bcast_entry(struct rvu *rvu, u16 pcifunc);
++void rvu_npc_enable_bcast_entry(struct rvu *rvu, u16 pcifunc, bool enable);
+ int rvu_npc_update_rxvlan(struct rvu *rvu, u16 pcifunc, int nixlf);
+ void rvu_npc_disable_mcam_entries(struct rvu *rvu, u16 pcifunc, int nixlf);
+ void rvu_npc_disable_default_entries(struct rvu *rvu, u16 pcifunc, int nixlf);
+diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+index 36953d4f51c73..3495b3a6828c0 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+@@ -17,7 +17,6 @@
+ #include "npc.h"
+ #include "cgx.h"
+
+-static int nix_update_bcast_mce_list(struct rvu *rvu, u16 pcifunc, bool add);
+ static int rvu_nix_get_bpid(struct rvu *rvu, struct nix_bp_cfg_req *req,
+ int type, int chan_id);
+
+@@ -2020,7 +2019,7 @@ static int nix_update_mce_list(struct nix_mce_list *mce_list,
+ return 0;
+ }
+
+-static int nix_update_bcast_mce_list(struct rvu *rvu, u16 pcifunc, bool add)
++int nix_update_bcast_mce_list(struct rvu *rvu, u16 pcifunc, bool add)
+ {
+ int err = 0, idx, next_idx, last_idx;
+ struct nix_mce_list *mce_list;
+@@ -2065,7 +2064,7 @@ static int nix_update_bcast_mce_list(struct rvu *rvu, u16 pcifunc, bool add)
+
+ /* Disable MCAM entry in NPC */
+ if (!mce_list->count) {
+- rvu_npc_disable_bcast_entry(rvu, pcifunc);
++ rvu_npc_enable_bcast_entry(rvu, pcifunc, false);
+ goto end;
+ }
+
+diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+index 0a214084406a6..fbaf9bcd83f2f 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+@@ -530,7 +530,7 @@ void rvu_npc_install_bcast_match_entry(struct rvu *rvu, u16 pcifunc,
+ NIX_INTF_RX, &entry, true);
+ }
+
+-void rvu_npc_disable_bcast_entry(struct rvu *rvu, u16 pcifunc)
++void rvu_npc_enable_bcast_entry(struct rvu *rvu, u16 pcifunc, bool enable)
+ {
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ int blkaddr, index;
+@@ -543,7 +543,7 @@ void rvu_npc_disable_bcast_entry(struct rvu *rvu, u16 pcifunc)
+ pcifunc = pcifunc & ~RVU_PFVF_FUNC_MASK;
+
+ index = npc_get_nixlf_mcam_index(mcam, pcifunc, 0, NIXLF_BCAST_ENTRY);
+- npc_enable_mcam_entry(rvu, mcam, blkaddr, index, false);
++ npc_enable_mcam_entry(rvu, mcam, blkaddr, index, enable);
+ }
+
+ void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf,
+@@ -622,23 +622,35 @@ static void npc_enadis_default_entries(struct rvu *rvu, u16 pcifunc,
+ nixlf, NIXLF_UCAST_ENTRY);
+ npc_enable_mcam_entry(rvu, mcam, blkaddr, index, enable);
+
+- /* For PF, ena/dis promisc and bcast MCAM match entries */
+- if (pcifunc & RVU_PFVF_FUNC_MASK)
++ /* For PF, ena/dis promisc and bcast MCAM match entries.
++ * For VFs add/delete from bcast list when RX multicast
++ * feature is present.
++ */
++ if (pcifunc & RVU_PFVF_FUNC_MASK && !rvu->hw->cap.nix_rx_multicast)
+ return;
+
+ /* For bcast, enable/disable only if it's action is not
+ * packet replication, incase if action is replication
+- * then this PF's nixlf is removed from bcast replication
++ * then this PF/VF's nixlf is removed from bcast replication
+ * list.
+ */
+- index = npc_get_nixlf_mcam_index(mcam, pcifunc,
++ index = npc_get_nixlf_mcam_index(mcam, pcifunc & ~RVU_PFVF_FUNC_MASK,
+ nixlf, NIXLF_BCAST_ENTRY);
+ bank = npc_get_bank(mcam, index);
+ *(u64 *)&action = rvu_read64(rvu, blkaddr,
+ NPC_AF_MCAMEX_BANKX_ACTION(index & (mcam->banksize - 1), bank));
+- if (action.op != NIX_RX_ACTIONOP_MCAST)
++
++ /* VFs will not have BCAST entry */
++ if (action.op != NIX_RX_ACTIONOP_MCAST &&
++ !(pcifunc & RVU_PFVF_FUNC_MASK)) {
+ npc_enable_mcam_entry(rvu, mcam,
+ blkaddr, index, enable);
++ } else {
++ nix_update_bcast_mce_list(rvu, pcifunc, enable);
++ /* Enable PF's BCAST entry for packet replication */
++ rvu_npc_enable_bcast_entry(rvu, pcifunc, enable);
++ }
++
+ if (enable)
+ rvu_npc_enable_promisc_entry(rvu, pcifunc, nixlf);
+ else
+diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+index 75a8c407e815c..2fb45670aca49 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+@@ -370,8 +370,8 @@ static int otx2_forward_vf_mbox_msgs(struct otx2_nic *pf,
+ dst_mbox = &pf->mbox;
+ dst_size = dst_mbox->mbox.tx_size -
+ ALIGN(sizeof(*mbox_hdr), MBOX_MSG_ALIGN);
+- /* Check if msgs fit into destination area */
+- if (mbox_hdr->msg_size > dst_size)
++ /* Check if msgs fit into destination area and has valid size */
++ if (mbox_hdr->msg_size > dst_size || !mbox_hdr->msg_size)
+ return -EINVAL;
+
+ dst_mdev = &dst_mbox->mbox.dev[0];
+@@ -526,10 +526,10 @@ static void otx2_pfvf_mbox_up_handler(struct work_struct *work)
+
+ end:
+ offset = mbox->rx_start + msg->next_msgoff;
++ if (mdev->msgs_acked == (vf_mbox->up_num_msgs - 1))
++ __otx2_mbox_reset(mbox, 0);
+ mdev->msgs_acked++;
+ }
+-
+- otx2_mbox_reset(mbox, vf_idx);
+ }
+
+ static irqreturn_t otx2_pfvf_mbox_intr_handler(int irq, void *pf_irq)
+@@ -803,10 +803,11 @@ static void otx2_pfaf_mbox_handler(struct work_struct *work)
+ msg = (struct mbox_msghdr *)(mdev->mbase + offset);
+ otx2_process_pfaf_mbox_msg(pf, msg);
+ offset = mbox->rx_start + msg->next_msgoff;
++ if (mdev->msgs_acked == (af_mbox->num_msgs - 1))
++ __otx2_mbox_reset(mbox, 0);
+ mdev->msgs_acked++;
+ }
+
+- otx2_mbox_reset(mbox, 0);
+ }
+
+ static void otx2_handle_link_event(struct otx2_nic *pf)
+@@ -1560,10 +1561,13 @@ int otx2_open(struct net_device *netdev)
+
+ err = otx2_rxtx_enable(pf, true);
+ if (err)
+- goto err_free_cints;
++ goto err_tx_stop_queues;
+
+ return 0;
+
++err_tx_stop_queues:
++ netif_tx_stop_all_queues(netdev);
++ netif_carrier_off(netdev);
+ err_free_cints:
+ otx2_free_cints(pf, qidx);
+ vec = pci_irq_vector(pf->pdev,
+diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
+index b04f5429d72d9..334eab976ee4a 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
+@@ -524,6 +524,7 @@ static void otx2_sqe_add_hdr(struct otx2_nic *pfvf, struct otx2_snd_queue *sq,
+ sqe_hdr->ol3type = NIX_SENDL3TYPE_IP4_CKSUM;
+ } else if (skb->protocol == htons(ETH_P_IPV6)) {
+ proto = ipv6_hdr(skb)->nexthdr;
++ sqe_hdr->ol3type = NIX_SENDL3TYPE_IP6;
+ }
+
+ if (proto == IPPROTO_TCP)
+diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
+index 92a3db69a6cd6..2f90f17214415 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
+@@ -99,10 +99,10 @@ static void otx2vf_vfaf_mbox_handler(struct work_struct *work)
+ msg = (struct mbox_msghdr *)(mdev->mbase + offset);
+ otx2vf_process_vfaf_mbox_msg(af_mbox->pfvf, msg);
+ offset = mbox->rx_start + msg->next_msgoff;
++ if (mdev->msgs_acked == (af_mbox->num_msgs - 1))
++ __otx2_mbox_reset(mbox, 0);
+ mdev->msgs_acked++;
+ }
+-
+- otx2_mbox_reset(mbox, 0);
+ }
+
+ static int otx2vf_process_mbox_msg_up(struct otx2_nic *vf,
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+index 1d91a0d0ab1d7..2b597ac365f84 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+@@ -69,12 +69,10 @@ enum {
+ MLX5_CMD_DELIVERY_STAT_CMD_DESCR_ERR = 0x10,
+ };
+
+-static struct mlx5_cmd_work_ent *alloc_cmd(struct mlx5_cmd *cmd,
+- struct mlx5_cmd_msg *in,
+- struct mlx5_cmd_msg *out,
+- void *uout, int uout_size,
+- mlx5_cmd_cbk_t cbk,
+- void *context, int page_queue)
++static struct mlx5_cmd_work_ent *
++cmd_alloc_ent(struct mlx5_cmd *cmd, struct mlx5_cmd_msg *in,
++ struct mlx5_cmd_msg *out, void *uout, int uout_size,
++ mlx5_cmd_cbk_t cbk, void *context, int page_queue)
+ {
+ gfp_t alloc_flags = cbk ? GFP_ATOMIC : GFP_KERNEL;
+ struct mlx5_cmd_work_ent *ent;
+@@ -83,6 +81,7 @@ static struct mlx5_cmd_work_ent *alloc_cmd(struct mlx5_cmd *cmd,
+ if (!ent)
+ return ERR_PTR(-ENOMEM);
+
++ ent->idx = -EINVAL;
+ ent->in = in;
+ ent->out = out;
+ ent->uout = uout;
+@@ -91,10 +90,16 @@ static struct mlx5_cmd_work_ent *alloc_cmd(struct mlx5_cmd *cmd,
+ ent->context = context;
+ ent->cmd = cmd;
+ ent->page_queue = page_queue;
++ refcount_set(&ent->refcnt, 1);
+
+ return ent;
+ }
+
++static void cmd_free_ent(struct mlx5_cmd_work_ent *ent)
++{
++ kfree(ent);
++}
++
+ static u8 alloc_token(struct mlx5_cmd *cmd)
+ {
+ u8 token;
+@@ -109,7 +114,7 @@ static u8 alloc_token(struct mlx5_cmd *cmd)
+ return token;
+ }
+
+-static int alloc_ent(struct mlx5_cmd *cmd)
++static int cmd_alloc_index(struct mlx5_cmd *cmd)
+ {
+ unsigned long flags;
+ int ret;
+@@ -123,7 +128,7 @@ static int alloc_ent(struct mlx5_cmd *cmd)
+ return ret < cmd->max_reg_cmds ? ret : -ENOMEM;
+ }
+
+-static void free_ent(struct mlx5_cmd *cmd, int idx)
++static void cmd_free_index(struct mlx5_cmd *cmd, int idx)
+ {
+ unsigned long flags;
+
+@@ -132,6 +137,22 @@ static void free_ent(struct mlx5_cmd *cmd, int idx)
+ spin_unlock_irqrestore(&cmd->alloc_lock, flags);
+ }
+
++static void cmd_ent_get(struct mlx5_cmd_work_ent *ent)
++{
++ refcount_inc(&ent->refcnt);
++}
++
++static void cmd_ent_put(struct mlx5_cmd_work_ent *ent)
++{
++ if (!refcount_dec_and_test(&ent->refcnt))
++ return;
++
++ if (ent->idx >= 0)
++ cmd_free_index(ent->cmd, ent->idx);
++
++ cmd_free_ent(ent);
++}
++
+ static struct mlx5_cmd_layout *get_inst(struct mlx5_cmd *cmd, int idx)
+ {
+ return cmd->cmd_buf + (idx << cmd->log_stride);
+@@ -219,11 +240,6 @@ static void poll_timeout(struct mlx5_cmd_work_ent *ent)
+ ent->ret = -ETIMEDOUT;
+ }
+
+-static void free_cmd(struct mlx5_cmd_work_ent *ent)
+-{
+- kfree(ent);
+-}
+-
+ static int verify_signature(struct mlx5_cmd_work_ent *ent)
+ {
+ struct mlx5_cmd_mailbox *next = ent->out->next;
+@@ -837,11 +853,22 @@ static void cb_timeout_handler(struct work_struct *work)
+ struct mlx5_core_dev *dev = container_of(ent->cmd, struct mlx5_core_dev,
+ cmd);
+
++ mlx5_cmd_eq_recover(dev);
++
++ /* Maybe got handled by eq recover ? */
++ if (!test_bit(MLX5_CMD_ENT_STATE_PENDING_COMP, &ent->state)) {
++ mlx5_core_warn(dev, "cmd[%d]: %s(0x%x) Async, recovered after timeout\n", ent->idx,
++ mlx5_command_str(msg_to_opcode(ent->in)), msg_to_opcode(ent->in));
++ goto out; /* phew, already handled */
++ }
++
+ ent->ret = -ETIMEDOUT;
+- mlx5_core_warn(dev, "%s(0x%x) timeout. Will cause a leak of a command resource\n",
+- mlx5_command_str(msg_to_opcode(ent->in)),
+- msg_to_opcode(ent->in));
++ mlx5_core_warn(dev, "cmd[%d]: %s(0x%x) Async, timeout. Will cause a leak of a command resource\n",
++ ent->idx, mlx5_command_str(msg_to_opcode(ent->in)), msg_to_opcode(ent->in));
+ mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
++
++out:
++ cmd_ent_put(ent); /* for the cmd_ent_get() took on schedule delayed work */
+ }
+
+ static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg);
+@@ -856,6 +883,25 @@ static bool opcode_allowed(struct mlx5_cmd *cmd, u16 opcode)
+ return cmd->allowed_opcode == opcode;
+ }
+
++static int cmd_alloc_index_retry(struct mlx5_cmd *cmd)
++{
++ unsigned long alloc_end = jiffies + msecs_to_jiffies(1000);
++ int idx;
++
++retry:
++ idx = cmd_alloc_index(cmd);
++ if (idx < 0 && time_before(jiffies, alloc_end)) {
++ /* Index allocation can fail on heavy load of commands. This is a temporary
++ * situation as the current command already holds the semaphore, meaning that
++ * another command completion is being handled and it is expected to release
++ * the entry index soon.
++ */
++ cpu_relax();
++ goto retry;
++ }
++ return idx;
++}
++
+ static void cmd_work_handler(struct work_struct *work)
+ {
+ struct mlx5_cmd_work_ent *ent = container_of(work, struct mlx5_cmd_work_ent, work);
+@@ -873,14 +919,14 @@ static void cmd_work_handler(struct work_struct *work)
+ sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem;
+ down(sem);
+ if (!ent->page_queue) {
+- alloc_ret = alloc_ent(cmd);
++ alloc_ret = cmd_alloc_index_retry(cmd);
+ if (alloc_ret < 0) {
+ mlx5_core_err_rl(dev, "failed to allocate command entry\n");
+ if (ent->callback) {
+ ent->callback(-EAGAIN, ent->context);
+ mlx5_free_cmd_msg(dev, ent->out);
+ free_msg(dev, ent->in);
+- free_cmd(ent);
++ cmd_ent_put(ent);
+ } else {
+ ent->ret = -EAGAIN;
+ complete(&ent->done);
+@@ -916,8 +962,8 @@ static void cmd_work_handler(struct work_struct *work)
+ ent->ts1 = ktime_get_ns();
+ cmd_mode = cmd->mode;
+
+- if (ent->callback)
+- schedule_delayed_work(&ent->cb_timeout_work, cb_timeout);
++ if (ent->callback && schedule_delayed_work(&ent->cb_timeout_work, cb_timeout))
++ cmd_ent_get(ent);
+ set_bit(MLX5_CMD_ENT_STATE_PENDING_COMP, &ent->state);
+
+ /* Skip sending command to fw if internal error */
+@@ -933,13 +979,10 @@ static void cmd_work_handler(struct work_struct *work)
+ MLX5_SET(mbox_out, ent->out, syndrome, drv_synd);
+
+ mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
+- /* no doorbell, no need to keep the entry */
+- free_ent(cmd, ent->idx);
+- if (ent->callback)
+- free_cmd(ent);
+ return;
+ }
+
++ cmd_ent_get(ent); /* for the _real_ FW event on completion */
+ /* ring doorbell after the descriptor is valid */
+ mlx5_core_dbg(dev, "writing 0x%x to command doorbell\n", 1 << ent->idx);
+ wmb();
+@@ -983,6 +1026,35 @@ static const char *deliv_status_to_str(u8 status)
+ }
+ }
+
++enum {
++ MLX5_CMD_TIMEOUT_RECOVER_MSEC = 5 * 1000,
++};
++
++static void wait_func_handle_exec_timeout(struct mlx5_core_dev *dev,
++ struct mlx5_cmd_work_ent *ent)
++{
++ unsigned long timeout = msecs_to_jiffies(MLX5_CMD_TIMEOUT_RECOVER_MSEC);
++
++ mlx5_cmd_eq_recover(dev);
++
++ /* Re-wait on the ent->done after executing the recovery flow. If the
++ * recovery flow (or any other recovery flow running simultaneously)
++ * has recovered an EQE, it should cause the entry to be completed by
++ * the command interface.
++ */
++ if (wait_for_completion_timeout(&ent->done, timeout)) {
++ mlx5_core_warn(dev, "cmd[%d]: %s(0x%x) recovered after timeout\n", ent->idx,
++ mlx5_command_str(msg_to_opcode(ent->in)), msg_to_opcode(ent->in));
++ return;
++ }
++
++ mlx5_core_warn(dev, "cmd[%d]: %s(0x%x) No done completion\n", ent->idx,
++ mlx5_command_str(msg_to_opcode(ent->in)), msg_to_opcode(ent->in));
++
++ ent->ret = -ETIMEDOUT;
++ mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
++}
++
+ static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent)
+ {
+ unsigned long timeout = msecs_to_jiffies(MLX5_CMD_TIMEOUT_MSEC);
+@@ -994,12 +1066,10 @@ static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent)
+ ent->ret = -ECANCELED;
+ goto out_err;
+ }
+- if (cmd->mode == CMD_MODE_POLLING || ent->polling) {
++ if (cmd->mode == CMD_MODE_POLLING || ent->polling)
+ wait_for_completion(&ent->done);
+- } else if (!wait_for_completion_timeout(&ent->done, timeout)) {
+- ent->ret = -ETIMEDOUT;
+- mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
+- }
++ else if (!wait_for_completion_timeout(&ent->done, timeout))
++ wait_func_handle_exec_timeout(dev, ent);
+
+ out_err:
+ err = ent->ret;
+@@ -1039,11 +1109,16 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
+ if (callback && page_queue)
+ return -EINVAL;
+
+- ent = alloc_cmd(cmd, in, out, uout, uout_size, callback, context,
+- page_queue);
++ ent = cmd_alloc_ent(cmd, in, out, uout, uout_size,
++ callback, context, page_queue);
+ if (IS_ERR(ent))
+ return PTR_ERR(ent);
+
++ /* put for this ent is when consumed, depending on the use case
++ * 1) (!callback) blocking flow: by caller after wait_func completes
++ * 2) (callback) flow: by mlx5_cmd_comp_handler() when ent is handled
++ */
++
+ ent->token = token;
+ ent->polling = force_polling;
+
+@@ -1062,12 +1137,10 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
+ }
+
+ if (callback)
+- goto out;
++ goto out; /* mlx5_cmd_comp_handler() will put(ent) */
+
+ err = wait_func(dev, ent);
+- if (err == -ETIMEDOUT)
+- goto out;
+- if (err == -ECANCELED)
++ if (err == -ETIMEDOUT || err == -ECANCELED)
+ goto out_free;
+
+ ds = ent->ts2 - ent->ts1;
+@@ -1085,7 +1158,7 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
+ *status = ent->status;
+
+ out_free:
+- free_cmd(ent);
++ cmd_ent_put(ent);
+ out:
+ return err;
+ }
+@@ -1516,14 +1589,19 @@ static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool force
+ if (!forced) {
+ mlx5_core_err(dev, "Command completion arrived after timeout (entry idx = %d).\n",
+ ent->idx);
+- free_ent(cmd, ent->idx);
+- free_cmd(ent);
++ cmd_ent_put(ent);
+ }
+ continue;
+ }
+
+- if (ent->callback)
+- cancel_delayed_work(&ent->cb_timeout_work);
++ if (ent->callback && cancel_delayed_work(&ent->cb_timeout_work))
++ cmd_ent_put(ent); /* timeout work was canceled */
++
++ if (!forced || /* Real FW completion */
++ pci_channel_offline(dev->pdev) || /* FW is inaccessible */
++ dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
++ cmd_ent_put(ent);
++
+ if (ent->page_queue)
+ sem = &cmd->pages_sem;
+ else
+@@ -1545,10 +1623,6 @@ static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool force
+ ent->ret, deliv_status_to_str(ent->status), ent->status);
+ }
+
+- /* only real completion will free the entry slot */
+- if (!forced)
+- free_ent(cmd, ent->idx);
+-
+ if (ent->callback) {
+ ds = ent->ts2 - ent->ts1;
+ if (ent->op < MLX5_CMD_OP_MAX) {
+@@ -1576,10 +1650,13 @@ static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool force
+ free_msg(dev, ent->in);
+
+ err = err ? err : ent->status;
+- if (!forced)
+- free_cmd(ent);
++ /* final consumer is done, release ent */
++ cmd_ent_put(ent);
+ callback(err, context);
+ } else {
++ /* release wait_func() so mlx5_cmd_invoke()
++ * can make the final ent_put()
++ */
+ complete(&ent->done);
+ }
+ up(sem);
+@@ -1589,8 +1666,11 @@ static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool force
+
+ void mlx5_cmd_trigger_completions(struct mlx5_core_dev *dev)
+ {
++ struct mlx5_cmd *cmd = &dev->cmd;
++ unsigned long bitmask;
+ unsigned long flags;
+ u64 vector;
++ int i;
+
+ /* wait for pending handlers to complete */
+ mlx5_eq_synchronize_cmd_irq(dev);
+@@ -1599,11 +1679,20 @@ void mlx5_cmd_trigger_completions(struct mlx5_core_dev *dev)
+ if (!vector)
+ goto no_trig;
+
++ bitmask = vector;
++ /* we must increment the allocated entries refcount before triggering the completions
++ * to guarantee pending commands will not get freed in the meanwhile.
++ * For that reason, it also has to be done inside the alloc_lock.
++ */
++ for_each_set_bit(i, &bitmask, (1 << cmd->log_sz))
++ cmd_ent_get(cmd->ent_arr[i]);
+ vector |= MLX5_TRIGGERED_CMD_COMP;
+ spin_unlock_irqrestore(&dev->cmd.alloc_lock, flags);
+
+ mlx5_core_dbg(dev, "vector 0x%llx\n", vector);
+ mlx5_cmd_comp_handler(dev, vector, true);
++ for_each_set_bit(i, &bitmask, (1 << cmd->log_sz))
++ cmd_ent_put(cmd->ent_arr[i]);
+ return;
+
+ no_trig:
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
+index 76b23ba7a4687..cb3857e136d62 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
+@@ -90,7 +90,12 @@ struct page_pool;
+ #define MLX5_MPWRQ_PAGES_PER_WQE BIT(MLX5_MPWRQ_WQE_PAGE_ORDER)
+
+ #define MLX5_MTT_OCTW(npages) (ALIGN(npages, 8) / 2)
+-#define MLX5E_REQUIRED_WQE_MTTS (ALIGN(MLX5_MPWRQ_PAGES_PER_WQE, 8))
++/* Add another page to MLX5E_REQUIRED_WQE_MTTS as a buffer between
++ * WQEs, This page will absorb write overflow by the hardware, when
++ * receiving packets larger than MTU. These oversize packets are
++ * dropped by the driver at a later stage.
++ */
++#define MLX5E_REQUIRED_WQE_MTTS (ALIGN(MLX5_MPWRQ_PAGES_PER_WQE + 1, 8))
+ #define MLX5E_LOG_ALIGNED_MPWQE_PPW (ilog2(MLX5E_REQUIRED_WQE_MTTS))
+ #define MLX5E_REQUIRED_MTTS(wqes) (wqes * MLX5E_REQUIRED_WQE_MTTS)
+ #define MLX5E_MAX_RQ_NUM_MTTS \
+@@ -621,6 +626,7 @@ struct mlx5e_rq {
+ u32 rqn;
+ struct mlx5_core_dev *mdev;
+ struct mlx5_core_mkey umr_mkey;
++ struct mlx5e_dma_info wqe_overflow;
+
+ /* XDP read-mostly */
+ struct xdp_rxq_info xdp_rxq;
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port.c b/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
+index 98e909bf3c1ec..3e32264cf6131 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
+@@ -566,6 +566,9 @@ int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u16 fec_policy)
+ if (fec_policy >= (1 << MLX5E_FEC_LLRS_272_257_1) && !fec_50g_per_lane)
+ return -EOPNOTSUPP;
+
++ if (fec_policy && !mlx5e_fec_in_caps(dev, fec_policy))
++ return -EOPNOTSUPP;
++
+ MLX5_SET(pplm_reg, in, local_port, 1);
+ err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
+ if (err)
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/neigh.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/neigh.c
+index c3d167fa944c7..6a9d783d129b2 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/neigh.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/neigh.c
+@@ -109,11 +109,25 @@ static void mlx5e_rep_neigh_stats_work(struct work_struct *work)
+ rtnl_unlock();
+ }
+
++struct neigh_update_work {
++ struct work_struct work;
++ struct neighbour *n;
++ struct mlx5e_neigh_hash_entry *nhe;
++};
++
++static void mlx5e_release_neigh_update_work(struct neigh_update_work *update_work)
++{
++ neigh_release(update_work->n);
++ mlx5e_rep_neigh_entry_release(update_work->nhe);
++ kfree(update_work);
++}
++
+ static void mlx5e_rep_neigh_update(struct work_struct *work)
+ {
+- struct mlx5e_neigh_hash_entry *nhe =
+- container_of(work, struct mlx5e_neigh_hash_entry, neigh_update_work);
+- struct neighbour *n = nhe->n;
++ struct neigh_update_work *update_work = container_of(work, struct neigh_update_work,
++ work);
++ struct mlx5e_neigh_hash_entry *nhe = update_work->nhe;
++ struct neighbour *n = update_work->n;
+ struct mlx5e_encap_entry *e;
+ unsigned char ha[ETH_ALEN];
+ struct mlx5e_priv *priv;
+@@ -145,30 +159,42 @@ static void mlx5e_rep_neigh_update(struct work_struct *work)
+ mlx5e_rep_update_flows(priv, e, neigh_connected, ha);
+ mlx5e_encap_put(priv, e);
+ }
+- mlx5e_rep_neigh_entry_release(nhe);
+ rtnl_unlock();
+- neigh_release(n);
++ mlx5e_release_neigh_update_work(update_work);
+ }
+
+-static void mlx5e_rep_queue_neigh_update_work(struct mlx5e_priv *priv,
+- struct mlx5e_neigh_hash_entry *nhe,
+- struct neighbour *n)
++static struct neigh_update_work *mlx5e_alloc_neigh_update_work(struct mlx5e_priv *priv,
++ struct neighbour *n)
+ {
+- /* Take a reference to ensure the neighbour and mlx5 encap
+- * entry won't be destructed until we drop the reference in
+- * delayed work.
+- */
+- neigh_hold(n);
++ struct neigh_update_work *update_work;
++ struct mlx5e_neigh_hash_entry *nhe;
++ struct mlx5e_neigh m_neigh = {};
+
+- /* This assignment is valid as long as the the neigh reference
+- * is taken
+- */
+- nhe->n = n;
++ update_work = kzalloc(sizeof(*update_work), GFP_ATOMIC);
++ if (WARN_ON(!update_work))
++ return NULL;
+
+- if (!queue_work(priv->wq, &nhe->neigh_update_work)) {
+- mlx5e_rep_neigh_entry_release(nhe);
+- neigh_release(n);
++ m_neigh.dev = n->dev;
++ m_neigh.family = n->ops->family;
++ memcpy(&m_neigh.dst_ip, n->primary_key, n->tbl->key_len);
++
++ /* Obtain reference to nhe as last step in order not to release it in
++ * atomic context.
++ */
++ rcu_read_lock();
++ nhe = mlx5e_rep_neigh_entry_lookup(priv, &m_neigh);
++ rcu_read_unlock();
++ if (!nhe) {
++ kfree(update_work);
++ return NULL;
+ }
++
++ INIT_WORK(&update_work->work, mlx5e_rep_neigh_update);
++ neigh_hold(n);
++ update_work->n = n;
++ update_work->nhe = nhe;
++
++ return update_work;
+ }
+
+ static int mlx5e_rep_netevent_event(struct notifier_block *nb,
+@@ -180,7 +206,7 @@ static int mlx5e_rep_netevent_event(struct notifier_block *nb,
+ struct net_device *netdev = rpriv->netdev;
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+ struct mlx5e_neigh_hash_entry *nhe = NULL;
+- struct mlx5e_neigh m_neigh = {};
++ struct neigh_update_work *update_work;
+ struct neigh_parms *p;
+ struct neighbour *n;
+ bool found = false;
+@@ -195,17 +221,11 @@ static int mlx5e_rep_netevent_event(struct notifier_block *nb,
+ #endif
+ return NOTIFY_DONE;
+
+- m_neigh.dev = n->dev;
+- m_neigh.family = n->ops->family;
+- memcpy(&m_neigh.dst_ip, n->primary_key, n->tbl->key_len);
+-
+- rcu_read_lock();
+- nhe = mlx5e_rep_neigh_entry_lookup(priv, &m_neigh);
+- rcu_read_unlock();
+- if (!nhe)
++ update_work = mlx5e_alloc_neigh_update_work(priv, n);
++ if (!update_work)
+ return NOTIFY_DONE;
+
+- mlx5e_rep_queue_neigh_update_work(priv, nhe, n);
++ queue_work(priv->wq, &update_work->work);
+ break;
+
+ case NETEVENT_DELAY_PROBE_TIME_UPDATE:
+@@ -351,7 +371,6 @@ int mlx5e_rep_neigh_entry_create(struct mlx5e_priv *priv,
+
+ (*nhe)->priv = priv;
+ memcpy(&(*nhe)->m_neigh, &e->m_neigh, sizeof(e->m_neigh));
+- INIT_WORK(&(*nhe)->neigh_update_work, mlx5e_rep_neigh_update);
+ spin_lock_init(&(*nhe)->encap_list_lock);
+ INIT_LIST_HEAD(&(*nhe)->encap_list);
+ refcount_set(&(*nhe)->refcnt, 1);
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c
+index 73d3dc07331f1..713dc210f710c 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c
+@@ -217,6 +217,9 @@ static int __mlx5e_add_vlan_rule(struct mlx5e_priv *priv,
+ break;
+ }
+
++ if (WARN_ONCE(*rule_p, "VLAN rule already exists type %d", rule_type))
++ return 0;
++
+ *rule_p = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1);
+
+ if (IS_ERR(*rule_p)) {
+@@ -397,8 +400,7 @@ static void mlx5e_add_vlan_rules(struct mlx5e_priv *priv)
+ for_each_set_bit(i, priv->fs.vlan.active_svlans, VLAN_N_VID)
+ mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_STAG_VID, i);
+
+- if (priv->fs.vlan.cvlan_filter_disabled &&
+- !(priv->netdev->flags & IFF_PROMISC))
++ if (priv->fs.vlan.cvlan_filter_disabled)
+ mlx5e_add_any_vid_rules(priv);
+ }
+
+@@ -415,8 +417,12 @@ static void mlx5e_del_vlan_rules(struct mlx5e_priv *priv)
+ for_each_set_bit(i, priv->fs.vlan.active_svlans, VLAN_N_VID)
+ mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_STAG_VID, i);
+
+- if (priv->fs.vlan.cvlan_filter_disabled &&
+- !(priv->netdev->flags & IFF_PROMISC))
++ WARN_ON_ONCE(!(test_bit(MLX5E_STATE_DESTROYING, &priv->state)));
++
++ /* must be called after DESTROY bit is set and
++ * set_rx_mode is called and flushed
++ */
++ if (priv->fs.vlan.cvlan_filter_disabled)
+ mlx5e_del_any_vid_rules(priv);
+ }
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index cccf65fc116ee..f8a20dd814379 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -258,12 +258,17 @@ static int mlx5e_rq_alloc_mpwqe_info(struct mlx5e_rq *rq,
+
+ static int mlx5e_create_umr_mkey(struct mlx5_core_dev *mdev,
+ u64 npages, u8 page_shift,
+- struct mlx5_core_mkey *umr_mkey)
++ struct mlx5_core_mkey *umr_mkey,
++ dma_addr_t filler_addr)
+ {
+- int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
++ struct mlx5_mtt *mtt;
++ int inlen;
+ void *mkc;
+ u32 *in;
+ int err;
++ int i;
++
++ inlen = MLX5_ST_SZ_BYTES(create_mkey_in) + sizeof(*mtt) * npages;
+
+ in = kvzalloc(inlen, GFP_KERNEL);
+ if (!in)
+@@ -283,6 +288,18 @@ static int mlx5e_create_umr_mkey(struct mlx5_core_dev *mdev,
+ MLX5_SET(mkc, mkc, translations_octword_size,
+ MLX5_MTT_OCTW(npages));
+ MLX5_SET(mkc, mkc, log_page_size, page_shift);
++ MLX5_SET(create_mkey_in, in, translations_octword_actual_size,
++ MLX5_MTT_OCTW(npages));
++
++ /* Initialize the mkey with all MTTs pointing to a default
++ * page (filler_addr). When the channels are activated, UMR
++ * WQEs will redirect the RX WQEs to the actual memory from
++ * the RQ's pool, while the gaps (wqe_overflow) remain mapped
++ * to the default page.
++ */
++ mtt = MLX5_ADDR_OF(create_mkey_in, in, klm_pas_mtt);
++ for (i = 0 ; i < npages ; i++)
++ mtt[i].ptag = cpu_to_be64(filler_addr);
+
+ err = mlx5_core_create_mkey(mdev, umr_mkey, in, inlen);
+
+@@ -294,7 +311,8 @@ static int mlx5e_create_rq_umr_mkey(struct mlx5_core_dev *mdev, struct mlx5e_rq
+ {
+ u64 num_mtts = MLX5E_REQUIRED_MTTS(mlx5_wq_ll_get_size(&rq->mpwqe.wq));
+
+- return mlx5e_create_umr_mkey(mdev, num_mtts, PAGE_SHIFT, &rq->umr_mkey);
++ return mlx5e_create_umr_mkey(mdev, num_mtts, PAGE_SHIFT, &rq->umr_mkey,
++ rq->wqe_overflow.addr);
+ }
+
+ static inline u64 mlx5e_get_mpwqe_offset(struct mlx5e_rq *rq, u16 wqe_ix)
+@@ -362,6 +380,28 @@ static void mlx5e_rq_err_cqe_work(struct work_struct *recover_work)
+ mlx5e_reporter_rq_cqe_err(rq);
+ }
+
++static int mlx5e_alloc_mpwqe_rq_drop_page(struct mlx5e_rq *rq)
++{
++ rq->wqe_overflow.page = alloc_page(GFP_KERNEL);
++ if (!rq->wqe_overflow.page)
++ return -ENOMEM;
++
++ rq->wqe_overflow.addr = dma_map_page(rq->pdev, rq->wqe_overflow.page, 0,
++ PAGE_SIZE, rq->buff.map_dir);
++ if (dma_mapping_error(rq->pdev, rq->wqe_overflow.addr)) {
++ __free_page(rq->wqe_overflow.page);
++ return -ENOMEM;
++ }
++ return 0;
++}
++
++static void mlx5e_free_mpwqe_rq_drop_page(struct mlx5e_rq *rq)
++{
++ dma_unmap_page(rq->pdev, rq->wqe_overflow.addr, PAGE_SIZE,
++ rq->buff.map_dir);
++ __free_page(rq->wqe_overflow.page);
++}
++
+ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
+ struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk,
+@@ -421,6 +461,10 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
+ if (err)
+ goto err_rq_wq_destroy;
+
++ err = mlx5e_alloc_mpwqe_rq_drop_page(rq);
++ if (err)
++ goto err_rq_wq_destroy;
++
+ rq->mpwqe.wq.db = &rq->mpwqe.wq.db[MLX5_RCV_DBR];
+
+ wq_sz = mlx5_wq_ll_get_size(&rq->mpwqe.wq);
+@@ -459,7 +503,7 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
+
+ err = mlx5e_create_rq_umr_mkey(mdev, rq);
+ if (err)
+- goto err_rq_wq_destroy;
++ goto err_rq_drop_page;
+ rq->mkey_be = cpu_to_be32(rq->umr_mkey.key);
+
+ err = mlx5e_rq_alloc_mpwqe_info(rq, c);
+@@ -598,6 +642,8 @@ err_free:
+ case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
+ kvfree(rq->mpwqe.info);
+ mlx5_core_destroy_mkey(mdev, &rq->umr_mkey);
++err_rq_drop_page:
++ mlx5e_free_mpwqe_rq_drop_page(rq);
+ break;
+ default: /* MLX5_WQ_TYPE_CYCLIC */
+ kvfree(rq->wqe.frags);
+@@ -631,6 +677,7 @@ static void mlx5e_free_rq(struct mlx5e_rq *rq)
+ case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
+ kvfree(rq->mpwqe.info);
+ mlx5_core_destroy_mkey(rq->mdev, &rq->umr_mkey);
++ mlx5e_free_mpwqe_rq_drop_page(rq);
+ break;
+ default: /* MLX5_WQ_TYPE_CYCLIC */
+ kvfree(rq->wqe.frags);
+@@ -4276,6 +4323,21 @@ void mlx5e_del_vxlan_port(struct net_device *netdev, struct udp_tunnel_info *ti)
+ mlx5e_vxlan_queue_work(priv, be16_to_cpu(ti->port), 0);
+ }
+
++static bool mlx5e_gre_tunnel_inner_proto_offload_supported(struct mlx5_core_dev *mdev,
++ struct sk_buff *skb)
++{
++ switch (skb->inner_protocol) {
++ case htons(ETH_P_IP):
++ case htons(ETH_P_IPV6):
++ case htons(ETH_P_TEB):
++ return true;
++ case htons(ETH_P_MPLS_UC):
++ case htons(ETH_P_MPLS_MC):
++ return MLX5_CAP_ETH(mdev, tunnel_stateless_mpls_over_gre);
++ }
++ return false;
++}
++
+ static netdev_features_t mlx5e_tunnel_features_check(struct mlx5e_priv *priv,
+ struct sk_buff *skb,
+ netdev_features_t features)
+@@ -4298,7 +4360,9 @@ static netdev_features_t mlx5e_tunnel_features_check(struct mlx5e_priv *priv,
+
+ switch (proto) {
+ case IPPROTO_GRE:
+- return features;
++ if (mlx5e_gre_tunnel_inner_proto_offload_supported(priv->mdev, skb))
++ return features;
++ break;
+ case IPPROTO_IPIP:
+ case IPPROTO_IPV6:
+ if (mlx5e_tunnel_proto_supported(priv->mdev, IPPROTO_IPIP))
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
+index 1d56698014843..fcaabafb2e56d 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
+@@ -133,12 +133,6 @@ struct mlx5e_neigh_hash_entry {
+ /* encap list sharing the same neigh */
+ struct list_head encap_list;
+
+- /* valid only when the neigh reference is taken during
+- * neigh_update_work workqueue callback.
+- */
+- struct neighbour *n;
+- struct work_struct neigh_update_work;
+-
+ /* neigh hash entry can be deleted only when the refcount is zero.
+ * refcount is needed to avoid neigh hash entry removal by TC, while
+ * it's used by the neigh notification call.
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+index 31ef9f8420c87..22a19d391e179 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+@@ -189,6 +189,29 @@ u32 mlx5_eq_poll_irq_disabled(struct mlx5_eq_comp *eq)
+ return count_eqe;
+ }
+
++static void mlx5_eq_async_int_lock(struct mlx5_eq_async *eq, unsigned long *flags)
++ __acquires(&eq->lock)
++{
++ if (in_irq())
++ spin_lock(&eq->lock);
++ else
++ spin_lock_irqsave(&eq->lock, *flags);
++}
++
++static void mlx5_eq_async_int_unlock(struct mlx5_eq_async *eq, unsigned long *flags)
++ __releases(&eq->lock)
++{
++ if (in_irq())
++ spin_unlock(&eq->lock);
++ else
++ spin_unlock_irqrestore(&eq->lock, *flags);
++}
++
++enum async_eq_nb_action {
++ ASYNC_EQ_IRQ_HANDLER = 0,
++ ASYNC_EQ_RECOVER = 1,
++};
++
+ static int mlx5_eq_async_int(struct notifier_block *nb,
+ unsigned long action, void *data)
+ {
+@@ -198,11 +221,14 @@ static int mlx5_eq_async_int(struct notifier_block *nb,
+ struct mlx5_eq_table *eqt;
+ struct mlx5_core_dev *dev;
+ struct mlx5_eqe *eqe;
++ unsigned long flags;
+ int num_eqes = 0;
+
+ dev = eq->dev;
+ eqt = dev->priv.eq_table;
+
++ mlx5_eq_async_int_lock(eq_async, &flags);
++
+ eqe = next_eqe_sw(eq);
+ if (!eqe)
+ goto out;
+@@ -223,8 +249,19 @@ static int mlx5_eq_async_int(struct notifier_block *nb,
+
+ out:
+ eq_update_ci(eq, 1);
++ mlx5_eq_async_int_unlock(eq_async, &flags);
+
+- return 0;
++ return unlikely(action == ASYNC_EQ_RECOVER) ? num_eqes : 0;
++}
++
++void mlx5_cmd_eq_recover(struct mlx5_core_dev *dev)
++{
++ struct mlx5_eq_async *eq = &dev->priv.eq_table->cmd_eq;
++ int eqes;
++
++ eqes = mlx5_eq_async_int(&eq->irq_nb, ASYNC_EQ_RECOVER, NULL);
++ if (eqes)
++ mlx5_core_warn(dev, "Recovered %d EQEs on cmd_eq\n", eqes);
+ }
+
+ static void init_eq_buf(struct mlx5_eq *eq)
+@@ -569,6 +606,7 @@ setup_async_eq(struct mlx5_core_dev *dev, struct mlx5_eq_async *eq,
+ int err;
+
+ eq->irq_nb.notifier_call = mlx5_eq_async_int;
++ spin_lock_init(&eq->lock);
+
+ err = create_async_eq(dev, &eq->core, param);
+ if (err) {
+@@ -656,8 +694,10 @@ static void destroy_async_eqs(struct mlx5_core_dev *dev)
+
+ cleanup_async_eq(dev, &table->pages_eq, "pages");
+ cleanup_async_eq(dev, &table->async_eq, "async");
++ mlx5_cmd_allowed_opcode(dev, MLX5_CMD_OP_DESTROY_EQ);
+ mlx5_cmd_use_polling(dev);
+ cleanup_async_eq(dev, &table->cmd_eq, "cmd");
++ mlx5_cmd_allowed_opcode(dev, CMD_ALLOWED_OPCODE_ALL);
+ mlx5_eq_notifier_unregister(dev, &table->cq_err_nb);
+ }
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h
+index 4aaca7400fb29..5c681e31983bc 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h
+@@ -37,6 +37,7 @@ struct mlx5_eq {
+ struct mlx5_eq_async {
+ struct mlx5_eq core;
+ struct notifier_block irq_nb;
++ spinlock_t lock; /* To avoid irq EQ handle races with resiliency flows */
+ };
+
+ struct mlx5_eq_comp {
+@@ -81,6 +82,7 @@ void mlx5_cq_tasklet_cb(unsigned long data);
+ struct cpumask *mlx5_eq_comp_cpumask(struct mlx5_core_dev *dev, int ix);
+
+ u32 mlx5_eq_poll_irq_disabled(struct mlx5_eq_comp *eq);
++void mlx5_cmd_eq_recover(struct mlx5_core_dev *dev);
+ void mlx5_eq_synchronize_async_irq(struct mlx5_core_dev *dev);
+ void mlx5_eq_synchronize_cmd_irq(struct mlx5_core_dev *dev);
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c b/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
+index 373981a659c7c..6fd9749203944 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
+@@ -115,7 +115,7 @@ static int request_irqs(struct mlx5_core_dev *dev, int nvec)
+ return 0;
+
+ err_request_irq:
+- for (; i >= 0; i--) {
++ while (i--) {
+ struct mlx5_irq *irq = mlx5_irq_get(dev, i);
+ int irqn = pci_irq_vector(dev->pdev, i);
+
+diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+index 5c020403342f9..7cccc41dd69c9 100644
+--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+@@ -292,13 +292,14 @@ mlxsw_sp_acl_tcam_group_add(struct mlxsw_sp_acl_tcam *tcam,
+ int err;
+
+ group->tcam = tcam;
+- mutex_init(&group->lock);
+ INIT_LIST_HEAD(&group->region_list);
+
+ err = mlxsw_sp_acl_tcam_group_id_get(tcam, &group->id);
+ if (err)
+ return err;
+
++ mutex_init(&group->lock);
++
+ return 0;
+ }
+
+diff --git a/drivers/net/ethernet/mscc/Makefile b/drivers/net/ethernet/mscc/Makefile
+index 91b33b55054e1..ad97a5cca6f99 100644
+--- a/drivers/net/ethernet/mscc/Makefile
++++ b/drivers/net/ethernet/mscc/Makefile
+@@ -2,4 +2,4 @@
+ obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot_common.o
+ mscc_ocelot_common-y := ocelot.o ocelot_io.o
+ mscc_ocelot_common-y += ocelot_regs.o ocelot_tc.o ocelot_police.o ocelot_ace.o ocelot_flower.o ocelot_ptp.o
+-obj-$(CONFIG_MSCC_OCELOT_SWITCH_OCELOT) += ocelot_board.o
++obj-$(CONFIG_MSCC_OCELOT_SWITCH_OCELOT) += ocelot_vsc7514.o
+diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
+index d0b79cca51840..61bbb7a090042 100644
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -396,18 +396,6 @@ static void ocelot_vlan_init(struct ocelot *ocelot)
+ }
+ }
+
+-/* Watermark encode
+- * Bit 8: Unit; 0:1, 1:16
+- * Bit 7-0: Value to be multiplied with unit
+- */
+-static u16 ocelot_wm_enc(u16 value)
+-{
+- if (value >= BIT(8))
+- return BIT(8) | (value / 16);
+-
+- return value;
+-}
+-
+ void ocelot_adjust_link(struct ocelot *ocelot, int port,
+ struct phy_device *phydev)
+ {
+@@ -2012,7 +2000,8 @@ void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu)
+ {
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+ int maxlen = sdu + ETH_HLEN + ETH_FCS_LEN;
+- int atop_wm;
++ int pause_start, pause_stop;
++ int atop, atop_tot;
+
+ if (port == ocelot->npi) {
+ maxlen += OCELOT_TAG_LEN;
+@@ -2025,20 +2014,20 @@ void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu)
+
+ ocelot_port_writel(ocelot_port, maxlen, DEV_MAC_MAXLEN_CFG);
+
+- /* Set Pause WM hysteresis
+- * 152 = 6 * maxlen / OCELOT_BUFFER_CELL_SZ
+- * 101 = 4 * maxlen / OCELOT_BUFFER_CELL_SZ
+- */
+- ocelot_write_rix(ocelot, SYS_PAUSE_CFG_PAUSE_ENA |
+- SYS_PAUSE_CFG_PAUSE_STOP(101) |
+- SYS_PAUSE_CFG_PAUSE_START(152), SYS_PAUSE_CFG, port);
++ /* Set Pause watermark hysteresis */
++ pause_start = 6 * maxlen / OCELOT_BUFFER_CELL_SZ;
++ pause_stop = 4 * maxlen / OCELOT_BUFFER_CELL_SZ;
++ ocelot_rmw_rix(ocelot, SYS_PAUSE_CFG_PAUSE_START(pause_start),
++ SYS_PAUSE_CFG_PAUSE_START_M, SYS_PAUSE_CFG, port);
++ ocelot_rmw_rix(ocelot, SYS_PAUSE_CFG_PAUSE_STOP(pause_stop),
++ SYS_PAUSE_CFG_PAUSE_STOP_M, SYS_PAUSE_CFG, port);
+
+- /* Tail dropping watermark */
+- atop_wm = (ocelot->shared_queue_sz - 9 * maxlen) /
++ /* Tail dropping watermarks */
++ atop_tot = (ocelot->shared_queue_sz - 9 * maxlen) /
+ OCELOT_BUFFER_CELL_SZ;
+- ocelot_write_rix(ocelot, ocelot_wm_enc(9 * maxlen),
+- SYS_ATOP, port);
+- ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG);
++ atop = (9 * maxlen) / OCELOT_BUFFER_CELL_SZ;
++ ocelot_write_rix(ocelot, ocelot->ops->wm_enc(atop), SYS_ATOP, port);
++ ocelot_write(ocelot, ocelot->ops->wm_enc(atop_tot), SYS_ATOP_TOT_CFG);
+ }
+ EXPORT_SYMBOL(ocelot_port_set_maxlen);
+
+@@ -2094,6 +2083,10 @@ void ocelot_init_port(struct ocelot *ocelot, int port)
+ ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_HIGH_CFG);
+ ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_LOW_CFG);
+
++ /* Enable transmission of pause frames */
++ ocelot_rmw_rix(ocelot, SYS_PAUSE_CFG_PAUSE_ENA, SYS_PAUSE_CFG_PAUSE_ENA,
++ SYS_PAUSE_CFG, port);
++
+ /* Drop frames with multicast source address */
+ ocelot_rmw_gix(ocelot, ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA,
+ ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA,
+diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c
+deleted file mode 100644
+index 4a15d2ff8b706..0000000000000
+--- a/drivers/net/ethernet/mscc/ocelot_board.c
++++ /dev/null
+@@ -1,626 +0,0 @@
+-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+-/*
+- * Microsemi Ocelot Switch driver
+- *
+- * Copyright (c) 2017 Microsemi Corporation
+- */
+-#include <linux/interrupt.h>
+-#include <linux/module.h>
+-#include <linux/of_net.h>
+-#include <linux/netdevice.h>
+-#include <linux/of_mdio.h>
+-#include <linux/of_platform.h>
+-#include <linux/mfd/syscon.h>
+-#include <linux/skbuff.h>
+-#include <net/switchdev.h>
+-
+-#include <soc/mscc/ocelot_vcap.h>
+-#include "ocelot.h"
+-
+-#define IFH_EXTRACT_BITFIELD64(x, o, w) (((x) >> (o)) & GENMASK_ULL((w) - 1, 0))
+-#define VSC7514_VCAP_IS2_CNT 64
+-#define VSC7514_VCAP_IS2_ENTRY_WIDTH 376
+-#define VSC7514_VCAP_IS2_ACTION_WIDTH 99
+-#define VSC7514_VCAP_PORT_CNT 11
+-
+-static int ocelot_parse_ifh(u32 *_ifh, struct frame_info *info)
+-{
+- u8 llen, wlen;
+- u64 ifh[2];
+-
+- ifh[0] = be64_to_cpu(((__force __be64 *)_ifh)[0]);
+- ifh[1] = be64_to_cpu(((__force __be64 *)_ifh)[1]);
+-
+- wlen = IFH_EXTRACT_BITFIELD64(ifh[0], 7, 8);
+- llen = IFH_EXTRACT_BITFIELD64(ifh[0], 15, 6);
+-
+- info->len = OCELOT_BUFFER_CELL_SZ * wlen + llen - 80;
+-
+- info->timestamp = IFH_EXTRACT_BITFIELD64(ifh[0], 21, 32);
+-
+- info->port = IFH_EXTRACT_BITFIELD64(ifh[1], 43, 4);
+-
+- info->tag_type = IFH_EXTRACT_BITFIELD64(ifh[1], 16, 1);
+- info->vid = IFH_EXTRACT_BITFIELD64(ifh[1], 0, 12);
+-
+- return 0;
+-}
+-
+-static int ocelot_rx_frame_word(struct ocelot *ocelot, u8 grp, bool ifh,
+- u32 *rval)
+-{
+- u32 val;
+- u32 bytes_valid;
+-
+- val = ocelot_read_rix(ocelot, QS_XTR_RD, grp);
+- if (val == XTR_NOT_READY) {
+- if (ifh)
+- return -EIO;
+-
+- do {
+- val = ocelot_read_rix(ocelot, QS_XTR_RD, grp);
+- } while (val == XTR_NOT_READY);
+- }
+-
+- switch (val) {
+- case XTR_ABORT:
+- return -EIO;
+- case XTR_EOF_0:
+- case XTR_EOF_1:
+- case XTR_EOF_2:
+- case XTR_EOF_3:
+- case XTR_PRUNED:
+- bytes_valid = XTR_VALID_BYTES(val);
+- val = ocelot_read_rix(ocelot, QS_XTR_RD, grp);
+- if (val == XTR_ESCAPE)
+- *rval = ocelot_read_rix(ocelot, QS_XTR_RD, grp);
+- else
+- *rval = val;
+-
+- return bytes_valid;
+- case XTR_ESCAPE:
+- *rval = ocelot_read_rix(ocelot, QS_XTR_RD, grp);
+-
+- return 4;
+- default:
+- *rval = val;
+-
+- return 4;
+- }
+-}
+-
+-static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
+-{
+- struct ocelot *ocelot = arg;
+- int i = 0, grp = 0;
+- int err = 0;
+-
+- if (!(ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp)))
+- return IRQ_NONE;
+-
+- do {
+- struct skb_shared_hwtstamps *shhwtstamps;
+- struct ocelot_port_private *priv;
+- struct ocelot_port *ocelot_port;
+- u64 tod_in_ns, full_ts_in_ns;
+- struct frame_info info = {};
+- struct net_device *dev;
+- u32 ifh[4], val, *buf;
+- struct timespec64 ts;
+- int sz, len, buf_len;
+- struct sk_buff *skb;
+-
+- for (i = 0; i < OCELOT_TAG_LEN / 4; i++) {
+- err = ocelot_rx_frame_word(ocelot, grp, true, &ifh[i]);
+- if (err != 4)
+- break;
+- }
+-
+- if (err != 4)
+- break;
+-
+- /* At this point the IFH was read correctly, so it is safe to
+- * presume that there is no error. The err needs to be reset
+- * otherwise a frame could come in CPU queue between the while
+- * condition and the check for error later on. And in that case
+- * the new frame is just removed and not processed.
+- */
+- err = 0;
+-
+- ocelot_parse_ifh(ifh, &info);
+-
+- ocelot_port = ocelot->ports[info.port];
+- priv = container_of(ocelot_port, struct ocelot_port_private,
+- port);
+- dev = priv->dev;
+-
+- skb = netdev_alloc_skb(dev, info.len);
+-
+- if (unlikely(!skb)) {
+- netdev_err(dev, "Unable to allocate sk_buff\n");
+- err = -ENOMEM;
+- break;
+- }
+- buf_len = info.len - ETH_FCS_LEN;
+- buf = (u32 *)skb_put(skb, buf_len);
+-
+- len = 0;
+- do {
+- sz = ocelot_rx_frame_word(ocelot, grp, false, &val);
+- *buf++ = val;
+- len += sz;
+- } while (len < buf_len);
+-
+- /* Read the FCS */
+- sz = ocelot_rx_frame_word(ocelot, grp, false, &val);
+- /* Update the statistics if part of the FCS was read before */
+- len -= ETH_FCS_LEN - sz;
+-
+- if (unlikely(dev->features & NETIF_F_RXFCS)) {
+- buf = (u32 *)skb_put(skb, ETH_FCS_LEN);
+- *buf = val;
+- }
+-
+- if (sz < 0) {
+- err = sz;
+- break;
+- }
+-
+- if (ocelot->ptp) {
+- ocelot_ptp_gettime64(&ocelot->ptp_info, &ts);
+-
+- tod_in_ns = ktime_set(ts.tv_sec, ts.tv_nsec);
+- if ((tod_in_ns & 0xffffffff) < info.timestamp)
+- full_ts_in_ns = (((tod_in_ns >> 32) - 1) << 32) |
+- info.timestamp;
+- else
+- full_ts_in_ns = (tod_in_ns & GENMASK_ULL(63, 32)) |
+- info.timestamp;
+-
+- shhwtstamps = skb_hwtstamps(skb);
+- memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
+- shhwtstamps->hwtstamp = full_ts_in_ns;
+- }
+-
+- /* Everything we see on an interface that is in the HW bridge
+- * has already been forwarded.
+- */
+- if (ocelot->bridge_mask & BIT(info.port))
+- skb->offload_fwd_mark = 1;
+-
+- skb->protocol = eth_type_trans(skb, dev);
+- if (!skb_defer_rx_timestamp(skb))
+- netif_rx(skb);
+- dev->stats.rx_bytes += len;
+- dev->stats.rx_packets++;
+- } while (ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp));
+-
+- if (err)
+- while (ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp))
+- ocelot_read_rix(ocelot, QS_XTR_RD, grp);
+-
+- return IRQ_HANDLED;
+-}
+-
+-static irqreturn_t ocelot_ptp_rdy_irq_handler(int irq, void *arg)
+-{
+- struct ocelot *ocelot = arg;
+-
+- ocelot_get_txtstamp(ocelot);
+-
+- return IRQ_HANDLED;
+-}
+-
+-static const struct of_device_id mscc_ocelot_match[] = {
+- { .compatible = "mscc,vsc7514-switch" },
+- { }
+-};
+-MODULE_DEVICE_TABLE(of, mscc_ocelot_match);
+-
+-static int ocelot_reset(struct ocelot *ocelot)
+-{
+- int retries = 100;
+- u32 val;
+-
+- regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], 1);
+- regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1);
+-
+- do {
+- msleep(1);
+- regmap_field_read(ocelot->regfields[SYS_RESET_CFG_MEM_INIT],
+- &val);
+- } while (val && --retries);
+-
+- if (!retries)
+- return -ETIMEDOUT;
+-
+- regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1);
+- regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1);
+-
+- return 0;
+-}
+-
+-static const struct ocelot_ops ocelot_ops = {
+- .reset = ocelot_reset,
+-};
+-
+-static const struct vcap_field vsc7514_vcap_is2_keys[] = {
+- /* Common: 46 bits */
+- [VCAP_IS2_TYPE] = { 0, 4},
+- [VCAP_IS2_HK_FIRST] = { 4, 1},
+- [VCAP_IS2_HK_PAG] = { 5, 8},
+- [VCAP_IS2_HK_IGR_PORT_MASK] = { 13, 12},
+- [VCAP_IS2_HK_RSV2] = { 25, 1},
+- [VCAP_IS2_HK_HOST_MATCH] = { 26, 1},
+- [VCAP_IS2_HK_L2_MC] = { 27, 1},
+- [VCAP_IS2_HK_L2_BC] = { 28, 1},
+- [VCAP_IS2_HK_VLAN_TAGGED] = { 29, 1},
+- [VCAP_IS2_HK_VID] = { 30, 12},
+- [VCAP_IS2_HK_DEI] = { 42, 1},
+- [VCAP_IS2_HK_PCP] = { 43, 3},
+- /* MAC_ETYPE / MAC_LLC / MAC_SNAP / OAM common */
+- [VCAP_IS2_HK_L2_DMAC] = { 46, 48},
+- [VCAP_IS2_HK_L2_SMAC] = { 94, 48},
+- /* MAC_ETYPE (TYPE=000) */
+- [VCAP_IS2_HK_MAC_ETYPE_ETYPE] = {142, 16},
+- [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0] = {158, 16},
+- [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD1] = {174, 8},
+- [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD2] = {182, 3},
+- /* MAC_LLC (TYPE=001) */
+- [VCAP_IS2_HK_MAC_LLC_L2_LLC] = {142, 40},
+- /* MAC_SNAP (TYPE=010) */
+- [VCAP_IS2_HK_MAC_SNAP_L2_SNAP] = {142, 40},
+- /* MAC_ARP (TYPE=011) */
+- [VCAP_IS2_HK_MAC_ARP_SMAC] = { 46, 48},
+- [VCAP_IS2_HK_MAC_ARP_ADDR_SPACE_OK] = { 94, 1},
+- [VCAP_IS2_HK_MAC_ARP_PROTO_SPACE_OK] = { 95, 1},
+- [VCAP_IS2_HK_MAC_ARP_LEN_OK] = { 96, 1},
+- [VCAP_IS2_HK_MAC_ARP_TARGET_MATCH] = { 97, 1},
+- [VCAP_IS2_HK_MAC_ARP_SENDER_MATCH] = { 98, 1},
+- [VCAP_IS2_HK_MAC_ARP_OPCODE_UNKNOWN] = { 99, 1},
+- [VCAP_IS2_HK_MAC_ARP_OPCODE] = {100, 2},
+- [VCAP_IS2_HK_MAC_ARP_L3_IP4_DIP] = {102, 32},
+- [VCAP_IS2_HK_MAC_ARP_L3_IP4_SIP] = {134, 32},
+- [VCAP_IS2_HK_MAC_ARP_DIP_EQ_SIP] = {166, 1},
+- /* IP4_TCP_UDP / IP4_OTHER common */
+- [VCAP_IS2_HK_IP4] = { 46, 1},
+- [VCAP_IS2_HK_L3_FRAGMENT] = { 47, 1},
+- [VCAP_IS2_HK_L3_FRAG_OFS_GT0] = { 48, 1},
+- [VCAP_IS2_HK_L3_OPTIONS] = { 49, 1},
+- [VCAP_IS2_HK_IP4_L3_TTL_GT0] = { 50, 1},
+- [VCAP_IS2_HK_L3_TOS] = { 51, 8},
+- [VCAP_IS2_HK_L3_IP4_DIP] = { 59, 32},
+- [VCAP_IS2_HK_L3_IP4_SIP] = { 91, 32},
+- [VCAP_IS2_HK_DIP_EQ_SIP] = {123, 1},
+- /* IP4_TCP_UDP (TYPE=100) */
+- [VCAP_IS2_HK_TCP] = {124, 1},
+- [VCAP_IS2_HK_L4_SPORT] = {125, 16},
+- [VCAP_IS2_HK_L4_DPORT] = {141, 16},
+- [VCAP_IS2_HK_L4_RNG] = {157, 8},
+- [VCAP_IS2_HK_L4_SPORT_EQ_DPORT] = {165, 1},
+- [VCAP_IS2_HK_L4_SEQUENCE_EQ0] = {166, 1},
+- [VCAP_IS2_HK_L4_URG] = {167, 1},
+- [VCAP_IS2_HK_L4_ACK] = {168, 1},
+- [VCAP_IS2_HK_L4_PSH] = {169, 1},
+- [VCAP_IS2_HK_L4_RST] = {170, 1},
+- [VCAP_IS2_HK_L4_SYN] = {171, 1},
+- [VCAP_IS2_HK_L4_FIN] = {172, 1},
+- [VCAP_IS2_HK_L4_1588_DOM] = {173, 8},
+- [VCAP_IS2_HK_L4_1588_VER] = {181, 4},
+- /* IP4_OTHER (TYPE=101) */
+- [VCAP_IS2_HK_IP4_L3_PROTO] = {124, 8},
+- [VCAP_IS2_HK_L3_PAYLOAD] = {132, 56},
+- /* IP6_STD (TYPE=110) */
+- [VCAP_IS2_HK_IP6_L3_TTL_GT0] = { 46, 1},
+- [VCAP_IS2_HK_L3_IP6_SIP] = { 47, 128},
+- [VCAP_IS2_HK_IP6_L3_PROTO] = {175, 8},
+- /* OAM (TYPE=111) */
+- [VCAP_IS2_HK_OAM_MEL_FLAGS] = {142, 7},
+- [VCAP_IS2_HK_OAM_VER] = {149, 5},
+- [VCAP_IS2_HK_OAM_OPCODE] = {154, 8},
+- [VCAP_IS2_HK_OAM_FLAGS] = {162, 8},
+- [VCAP_IS2_HK_OAM_MEPID] = {170, 16},
+- [VCAP_IS2_HK_OAM_CCM_CNTS_EQ0] = {186, 1},
+- [VCAP_IS2_HK_OAM_IS_Y1731] = {187, 1},
+-};
+-
+-static const struct vcap_field vsc7514_vcap_is2_actions[] = {
+- [VCAP_IS2_ACT_HIT_ME_ONCE] = { 0, 1},
+- [VCAP_IS2_ACT_CPU_COPY_ENA] = { 1, 1},
+- [VCAP_IS2_ACT_CPU_QU_NUM] = { 2, 3},
+- [VCAP_IS2_ACT_MASK_MODE] = { 5, 2},
+- [VCAP_IS2_ACT_MIRROR_ENA] = { 7, 1},
+- [VCAP_IS2_ACT_LRN_DIS] = { 8, 1},
+- [VCAP_IS2_ACT_POLICE_ENA] = { 9, 1},
+- [VCAP_IS2_ACT_POLICE_IDX] = { 10, 9},
+- [VCAP_IS2_ACT_POLICE_VCAP_ONLY] = { 19, 1},
+- [VCAP_IS2_ACT_PORT_MASK] = { 20, 11},
+- [VCAP_IS2_ACT_REW_OP] = { 31, 9},
+- [VCAP_IS2_ACT_SMAC_REPLACE_ENA] = { 40, 1},
+- [VCAP_IS2_ACT_RSV] = { 41, 2},
+- [VCAP_IS2_ACT_ACL_ID] = { 43, 6},
+- [VCAP_IS2_ACT_HIT_CNT] = { 49, 32},
+-};
+-
+-static const struct vcap_props vsc7514_vcap_props[] = {
+- [VCAP_IS2] = {
+- .tg_width = 2,
+- .sw_count = 4,
+- .entry_count = VSC7514_VCAP_IS2_CNT,
+- .entry_width = VSC7514_VCAP_IS2_ENTRY_WIDTH,
+- .action_count = VSC7514_VCAP_IS2_CNT +
+- VSC7514_VCAP_PORT_CNT + 2,
+- .action_width = 99,
+- .action_type_width = 1,
+- .action_table = {
+- [IS2_ACTION_TYPE_NORMAL] = {
+- .width = 49,
+- .count = 2
+- },
+- [IS2_ACTION_TYPE_SMAC_SIP] = {
+- .width = 6,
+- .count = 4
+- },
+- },
+- .counter_words = 4,
+- .counter_width = 32,
+- },
+-};
+-
+-static struct ptp_clock_info ocelot_ptp_clock_info = {
+- .owner = THIS_MODULE,
+- .name = "ocelot ptp",
+- .max_adj = 0x7fffffff,
+- .n_alarm = 0,
+- .n_ext_ts = 0,
+- .n_per_out = OCELOT_PTP_PINS_NUM,
+- .n_pins = OCELOT_PTP_PINS_NUM,
+- .pps = 0,
+- .gettime64 = ocelot_ptp_gettime64,
+- .settime64 = ocelot_ptp_settime64,
+- .adjtime = ocelot_ptp_adjtime,
+- .adjfine = ocelot_ptp_adjfine,
+- .verify = ocelot_ptp_verify,
+- .enable = ocelot_ptp_enable,
+-};
+-
+-static int mscc_ocelot_probe(struct platform_device *pdev)
+-{
+- struct device_node *np = pdev->dev.of_node;
+- struct device_node *ports, *portnp;
+- int err, irq_xtr, irq_ptp_rdy;
+- struct ocelot *ocelot;
+- struct regmap *hsio;
+- unsigned int i;
+-
+- struct {
+- enum ocelot_target id;
+- char *name;
+- u8 optional:1;
+- } io_target[] = {
+- { SYS, "sys" },
+- { REW, "rew" },
+- { QSYS, "qsys" },
+- { ANA, "ana" },
+- { QS, "qs" },
+- { S2, "s2" },
+- { PTP, "ptp", 1 },
+- };
+-
+- if (!np && !pdev->dev.platform_data)
+- return -ENODEV;
+-
+- ocelot = devm_kzalloc(&pdev->dev, sizeof(*ocelot), GFP_KERNEL);
+- if (!ocelot)
+- return -ENOMEM;
+-
+- platform_set_drvdata(pdev, ocelot);
+- ocelot->dev = &pdev->dev;
+-
+- for (i = 0; i < ARRAY_SIZE(io_target); i++) {
+- struct regmap *target;
+- struct resource *res;
+-
+- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+- io_target[i].name);
+-
+- target = ocelot_regmap_init(ocelot, res);
+- if (IS_ERR(target)) {
+- if (io_target[i].optional) {
+- ocelot->targets[io_target[i].id] = NULL;
+- continue;
+- }
+- return PTR_ERR(target);
+- }
+-
+- ocelot->targets[io_target[i].id] = target;
+- }
+-
+- hsio = syscon_regmap_lookup_by_compatible("mscc,ocelot-hsio");
+- if (IS_ERR(hsio)) {
+- dev_err(&pdev->dev, "missing hsio syscon\n");
+- return PTR_ERR(hsio);
+- }
+-
+- ocelot->targets[HSIO] = hsio;
+-
+- err = ocelot_chip_init(ocelot, &ocelot_ops);
+- if (err)
+- return err;
+-
+- irq_xtr = platform_get_irq_byname(pdev, "xtr");
+- if (irq_xtr < 0)
+- return -ENODEV;
+-
+- err = devm_request_threaded_irq(&pdev->dev, irq_xtr, NULL,
+- ocelot_xtr_irq_handler, IRQF_ONESHOT,
+- "frame extraction", ocelot);
+- if (err)
+- return err;
+-
+- irq_ptp_rdy = platform_get_irq_byname(pdev, "ptp_rdy");
+- if (irq_ptp_rdy > 0 && ocelot->targets[PTP]) {
+- err = devm_request_threaded_irq(&pdev->dev, irq_ptp_rdy, NULL,
+- ocelot_ptp_rdy_irq_handler,
+- IRQF_ONESHOT, "ptp ready",
+- ocelot);
+- if (err)
+- return err;
+-
+- /* Both the PTP interrupt and the PTP bank are available */
+- ocelot->ptp = 1;
+- }
+-
+- ports = of_get_child_by_name(np, "ethernet-ports");
+- if (!ports) {
+- dev_err(&pdev->dev, "no ethernet-ports child node found\n");
+- return -ENODEV;
+- }
+-
+- ocelot->num_phys_ports = of_get_child_count(ports);
+-
+- ocelot->ports = devm_kcalloc(&pdev->dev, ocelot->num_phys_ports,
+- sizeof(struct ocelot_port *), GFP_KERNEL);
+-
+- ocelot->vcap_is2_keys = vsc7514_vcap_is2_keys;
+- ocelot->vcap_is2_actions = vsc7514_vcap_is2_actions;
+- ocelot->vcap = vsc7514_vcap_props;
+-
+- ocelot_init(ocelot);
+- if (ocelot->ptp) {
+- err = ocelot_init_timestamp(ocelot, &ocelot_ptp_clock_info);
+- if (err) {
+- dev_err(ocelot->dev,
+- "Timestamp initialization failed\n");
+- ocelot->ptp = 0;
+- }
+- }
+-
+- /* No NPI port */
+- ocelot_configure_cpu(ocelot, -1, OCELOT_TAG_PREFIX_NONE,
+- OCELOT_TAG_PREFIX_NONE);
+-
+- for_each_available_child_of_node(ports, portnp) {
+- struct ocelot_port_private *priv;
+- struct ocelot_port *ocelot_port;
+- struct device_node *phy_node;
+- phy_interface_t phy_mode;
+- struct phy_device *phy;
+- struct resource *res;
+- struct phy *serdes;
+- void __iomem *regs;
+- char res_name[8];
+- u32 port;
+-
+- if (of_property_read_u32(portnp, "reg", &port))
+- continue;
+-
+- snprintf(res_name, sizeof(res_name), "port%d", port);
+-
+- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+- res_name);
+- regs = devm_ioremap_resource(&pdev->dev, res);
+- if (IS_ERR(regs))
+- continue;
+-
+- phy_node = of_parse_phandle(portnp, "phy-handle", 0);
+- if (!phy_node)
+- continue;
+-
+- phy = of_phy_find_device(phy_node);
+- of_node_put(phy_node);
+- if (!phy)
+- continue;
+-
+- err = ocelot_probe_port(ocelot, port, regs, phy);
+- if (err) {
+- of_node_put(portnp);
+- goto out_put_ports;
+- }
+-
+- ocelot_port = ocelot->ports[port];
+- priv = container_of(ocelot_port, struct ocelot_port_private,
+- port);
+-
+- of_get_phy_mode(portnp, &phy_mode);
+-
+- ocelot_port->phy_mode = phy_mode;
+-
+- switch (ocelot_port->phy_mode) {
+- case PHY_INTERFACE_MODE_NA:
+- continue;
+- case PHY_INTERFACE_MODE_SGMII:
+- break;
+- case PHY_INTERFACE_MODE_QSGMII:
+- /* Ensure clock signals and speed is set on all
+- * QSGMII links
+- */
+- ocelot_port_writel(ocelot_port,
+- DEV_CLOCK_CFG_LINK_SPEED
+- (OCELOT_SPEED_1000),
+- DEV_CLOCK_CFG);
+- break;
+- default:
+- dev_err(ocelot->dev,
+- "invalid phy mode for port%d, (Q)SGMII only\n",
+- port);
+- of_node_put(portnp);
+- err = -EINVAL;
+- goto out_put_ports;
+- }
+-
+- serdes = devm_of_phy_get(ocelot->dev, portnp, NULL);
+- if (IS_ERR(serdes)) {
+- err = PTR_ERR(serdes);
+- if (err == -EPROBE_DEFER)
+- dev_dbg(ocelot->dev, "deferring probe\n");
+- else
+- dev_err(ocelot->dev,
+- "missing SerDes phys for port%d\n",
+- port);
+-
+- of_node_put(portnp);
+- goto out_put_ports;
+- }
+-
+- priv->serdes = serdes;
+- }
+-
+- register_netdevice_notifier(&ocelot_netdevice_nb);
+- register_switchdev_notifier(&ocelot_switchdev_nb);
+- register_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb);
+-
+- dev_info(&pdev->dev, "Ocelot switch probed\n");
+-
+-out_put_ports:
+- of_node_put(ports);
+- return err;
+-}
+-
+-static int mscc_ocelot_remove(struct platform_device *pdev)
+-{
+- struct ocelot *ocelot = platform_get_drvdata(pdev);
+-
+- ocelot_deinit_timestamp(ocelot);
+- ocelot_deinit(ocelot);
+- unregister_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb);
+- unregister_switchdev_notifier(&ocelot_switchdev_nb);
+- unregister_netdevice_notifier(&ocelot_netdevice_nb);
+-
+- return 0;
+-}
+-
+-static struct platform_driver mscc_ocelot_driver = {
+- .probe = mscc_ocelot_probe,
+- .remove = mscc_ocelot_remove,
+- .driver = {
+- .name = "ocelot-switch",
+- .of_match_table = mscc_ocelot_match,
+- },
+-};
+-
+-module_platform_driver(mscc_ocelot_driver);
+-
+-MODULE_DESCRIPTION("Microsemi Ocelot switch driver");
+-MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>");
+-MODULE_LICENSE("Dual MIT/GPL");
+diff --git a/drivers/net/ethernet/mscc/ocelot_vsc7514.c b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
+new file mode 100644
+index 0000000000000..66b58b242f778
+--- /dev/null
++++ b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
+@@ -0,0 +1,639 @@
++// SPDX-License-Identifier: (GPL-2.0 OR MIT)
++/*
++ * Microsemi Ocelot Switch driver
++ *
++ * Copyright (c) 2017 Microsemi Corporation
++ */
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/of_net.h>
++#include <linux/netdevice.h>
++#include <linux/of_mdio.h>
++#include <linux/of_platform.h>
++#include <linux/mfd/syscon.h>
++#include <linux/skbuff.h>
++#include <net/switchdev.h>
++
++#include <soc/mscc/ocelot_vcap.h>
++#include "ocelot.h"
++
++#define IFH_EXTRACT_BITFIELD64(x, o, w) (((x) >> (o)) & GENMASK_ULL((w) - 1, 0))
++#define VSC7514_VCAP_IS2_CNT 64
++#define VSC7514_VCAP_IS2_ENTRY_WIDTH 376
++#define VSC7514_VCAP_IS2_ACTION_WIDTH 99
++#define VSC7514_VCAP_PORT_CNT 11
++
++static int ocelot_parse_ifh(u32 *_ifh, struct frame_info *info)
++{
++ u8 llen, wlen;
++ u64 ifh[2];
++
++ ifh[0] = be64_to_cpu(((__force __be64 *)_ifh)[0]);
++ ifh[1] = be64_to_cpu(((__force __be64 *)_ifh)[1]);
++
++ wlen = IFH_EXTRACT_BITFIELD64(ifh[0], 7, 8);
++ llen = IFH_EXTRACT_BITFIELD64(ifh[0], 15, 6);
++
++ info->len = OCELOT_BUFFER_CELL_SZ * wlen + llen - 80;
++
++ info->timestamp = IFH_EXTRACT_BITFIELD64(ifh[0], 21, 32);
++
++ info->port = IFH_EXTRACT_BITFIELD64(ifh[1], 43, 4);
++
++ info->tag_type = IFH_EXTRACT_BITFIELD64(ifh[1], 16, 1);
++ info->vid = IFH_EXTRACT_BITFIELD64(ifh[1], 0, 12);
++
++ return 0;
++}
++
++static int ocelot_rx_frame_word(struct ocelot *ocelot, u8 grp, bool ifh,
++ u32 *rval)
++{
++ u32 val;
++ u32 bytes_valid;
++
++ val = ocelot_read_rix(ocelot, QS_XTR_RD, grp);
++ if (val == XTR_NOT_READY) {
++ if (ifh)
++ return -EIO;
++
++ do {
++ val = ocelot_read_rix(ocelot, QS_XTR_RD, grp);
++ } while (val == XTR_NOT_READY);
++ }
++
++ switch (val) {
++ case XTR_ABORT:
++ return -EIO;
++ case XTR_EOF_0:
++ case XTR_EOF_1:
++ case XTR_EOF_2:
++ case XTR_EOF_3:
++ case XTR_PRUNED:
++ bytes_valid = XTR_VALID_BYTES(val);
++ val = ocelot_read_rix(ocelot, QS_XTR_RD, grp);
++ if (val == XTR_ESCAPE)
++ *rval = ocelot_read_rix(ocelot, QS_XTR_RD, grp);
++ else
++ *rval = val;
++
++ return bytes_valid;
++ case XTR_ESCAPE:
++ *rval = ocelot_read_rix(ocelot, QS_XTR_RD, grp);
++
++ return 4;
++ default:
++ *rval = val;
++
++ return 4;
++ }
++}
++
++static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
++{
++ struct ocelot *ocelot = arg;
++ int i = 0, grp = 0;
++ int err = 0;
++
++ if (!(ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp)))
++ return IRQ_NONE;
++
++ do {
++ struct skb_shared_hwtstamps *shhwtstamps;
++ struct ocelot_port_private *priv;
++ struct ocelot_port *ocelot_port;
++ u64 tod_in_ns, full_ts_in_ns;
++ struct frame_info info = {};
++ struct net_device *dev;
++ u32 ifh[4], val, *buf;
++ struct timespec64 ts;
++ int sz, len, buf_len;
++ struct sk_buff *skb;
++
++ for (i = 0; i < OCELOT_TAG_LEN / 4; i++) {
++ err = ocelot_rx_frame_word(ocelot, grp, true, &ifh[i]);
++ if (err != 4)
++ break;
++ }
++
++ if (err != 4)
++ break;
++
++ /* At this point the IFH was read correctly, so it is safe to
++ * presume that there is no error. The err needs to be reset
++ * otherwise a frame could come in CPU queue between the while
++ * condition and the check for error later on. And in that case
++ * the new frame is just removed and not processed.
++ */
++ err = 0;
++
++ ocelot_parse_ifh(ifh, &info);
++
++ ocelot_port = ocelot->ports[info.port];
++ priv = container_of(ocelot_port, struct ocelot_port_private,
++ port);
++ dev = priv->dev;
++
++ skb = netdev_alloc_skb(dev, info.len);
++
++ if (unlikely(!skb)) {
++ netdev_err(dev, "Unable to allocate sk_buff\n");
++ err = -ENOMEM;
++ break;
++ }
++ buf_len = info.len - ETH_FCS_LEN;
++ buf = (u32 *)skb_put(skb, buf_len);
++
++ len = 0;
++ do {
++ sz = ocelot_rx_frame_word(ocelot, grp, false, &val);
++ *buf++ = val;
++ len += sz;
++ } while (len < buf_len);
++
++ /* Read the FCS */
++ sz = ocelot_rx_frame_word(ocelot, grp, false, &val);
++ /* Update the statistics if part of the FCS was read before */
++ len -= ETH_FCS_LEN - sz;
++
++ if (unlikely(dev->features & NETIF_F_RXFCS)) {
++ buf = (u32 *)skb_put(skb, ETH_FCS_LEN);
++ *buf = val;
++ }
++
++ if (sz < 0) {
++ err = sz;
++ break;
++ }
++
++ if (ocelot->ptp) {
++ ocelot_ptp_gettime64(&ocelot->ptp_info, &ts);
++
++ tod_in_ns = ktime_set(ts.tv_sec, ts.tv_nsec);
++ if ((tod_in_ns & 0xffffffff) < info.timestamp)
++ full_ts_in_ns = (((tod_in_ns >> 32) - 1) << 32) |
++ info.timestamp;
++ else
++ full_ts_in_ns = (tod_in_ns & GENMASK_ULL(63, 32)) |
++ info.timestamp;
++
++ shhwtstamps = skb_hwtstamps(skb);
++ memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
++ shhwtstamps->hwtstamp = full_ts_in_ns;
++ }
++
++ /* Everything we see on an interface that is in the HW bridge
++ * has already been forwarded.
++ */
++ if (ocelot->bridge_mask & BIT(info.port))
++ skb->offload_fwd_mark = 1;
++
++ skb->protocol = eth_type_trans(skb, dev);
++ if (!skb_defer_rx_timestamp(skb))
++ netif_rx(skb);
++ dev->stats.rx_bytes += len;
++ dev->stats.rx_packets++;
++ } while (ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp));
++
++ if (err)
++ while (ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp))
++ ocelot_read_rix(ocelot, QS_XTR_RD, grp);
++
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t ocelot_ptp_rdy_irq_handler(int irq, void *arg)
++{
++ struct ocelot *ocelot = arg;
++
++ ocelot_get_txtstamp(ocelot);
++
++ return IRQ_HANDLED;
++}
++
++static const struct of_device_id mscc_ocelot_match[] = {
++ { .compatible = "mscc,vsc7514-switch" },
++ { }
++};
++MODULE_DEVICE_TABLE(of, mscc_ocelot_match);
++
++static int ocelot_reset(struct ocelot *ocelot)
++{
++ int retries = 100;
++ u32 val;
++
++ regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], 1);
++ regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1);
++
++ do {
++ msleep(1);
++ regmap_field_read(ocelot->regfields[SYS_RESET_CFG_MEM_INIT],
++ &val);
++ } while (val && --retries);
++
++ if (!retries)
++ return -ETIMEDOUT;
++
++ regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1);
++ regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1);
++
++ return 0;
++}
++
++/* Watermark encode
++ * Bit 8: Unit; 0:1, 1:16
++ * Bit 7-0: Value to be multiplied with unit
++ */
++static u16 ocelot_wm_enc(u16 value)
++{
++ if (value >= BIT(8))
++ return BIT(8) | (value / 16);
++
++ return value;
++}
++
++static const struct ocelot_ops ocelot_ops = {
++ .reset = ocelot_reset,
++ .wm_enc = ocelot_wm_enc,
++};
++
++static const struct vcap_field vsc7514_vcap_is2_keys[] = {
++ /* Common: 46 bits */
++ [VCAP_IS2_TYPE] = { 0, 4},
++ [VCAP_IS2_HK_FIRST] = { 4, 1},
++ [VCAP_IS2_HK_PAG] = { 5, 8},
++ [VCAP_IS2_HK_IGR_PORT_MASK] = { 13, 12},
++ [VCAP_IS2_HK_RSV2] = { 25, 1},
++ [VCAP_IS2_HK_HOST_MATCH] = { 26, 1},
++ [VCAP_IS2_HK_L2_MC] = { 27, 1},
++ [VCAP_IS2_HK_L2_BC] = { 28, 1},
++ [VCAP_IS2_HK_VLAN_TAGGED] = { 29, 1},
++ [VCAP_IS2_HK_VID] = { 30, 12},
++ [VCAP_IS2_HK_DEI] = { 42, 1},
++ [VCAP_IS2_HK_PCP] = { 43, 3},
++ /* MAC_ETYPE / MAC_LLC / MAC_SNAP / OAM common */
++ [VCAP_IS2_HK_L2_DMAC] = { 46, 48},
++ [VCAP_IS2_HK_L2_SMAC] = { 94, 48},
++ /* MAC_ETYPE (TYPE=000) */
++ [VCAP_IS2_HK_MAC_ETYPE_ETYPE] = {142, 16},
++ [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0] = {158, 16},
++ [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD1] = {174, 8},
++ [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD2] = {182, 3},
++ /* MAC_LLC (TYPE=001) */
++ [VCAP_IS2_HK_MAC_LLC_L2_LLC] = {142, 40},
++ /* MAC_SNAP (TYPE=010) */
++ [VCAP_IS2_HK_MAC_SNAP_L2_SNAP] = {142, 40},
++ /* MAC_ARP (TYPE=011) */
++ [VCAP_IS2_HK_MAC_ARP_SMAC] = { 46, 48},
++ [VCAP_IS2_HK_MAC_ARP_ADDR_SPACE_OK] = { 94, 1},
++ [VCAP_IS2_HK_MAC_ARP_PROTO_SPACE_OK] = { 95, 1},
++ [VCAP_IS2_HK_MAC_ARP_LEN_OK] = { 96, 1},
++ [VCAP_IS2_HK_MAC_ARP_TARGET_MATCH] = { 97, 1},
++ [VCAP_IS2_HK_MAC_ARP_SENDER_MATCH] = { 98, 1},
++ [VCAP_IS2_HK_MAC_ARP_OPCODE_UNKNOWN] = { 99, 1},
++ [VCAP_IS2_HK_MAC_ARP_OPCODE] = {100, 2},
++ [VCAP_IS2_HK_MAC_ARP_L3_IP4_DIP] = {102, 32},
++ [VCAP_IS2_HK_MAC_ARP_L3_IP4_SIP] = {134, 32},
++ [VCAP_IS2_HK_MAC_ARP_DIP_EQ_SIP] = {166, 1},
++ /* IP4_TCP_UDP / IP4_OTHER common */
++ [VCAP_IS2_HK_IP4] = { 46, 1},
++ [VCAP_IS2_HK_L3_FRAGMENT] = { 47, 1},
++ [VCAP_IS2_HK_L3_FRAG_OFS_GT0] = { 48, 1},
++ [VCAP_IS2_HK_L3_OPTIONS] = { 49, 1},
++ [VCAP_IS2_HK_IP4_L3_TTL_GT0] = { 50, 1},
++ [VCAP_IS2_HK_L3_TOS] = { 51, 8},
++ [VCAP_IS2_HK_L3_IP4_DIP] = { 59, 32},
++ [VCAP_IS2_HK_L3_IP4_SIP] = { 91, 32},
++ [VCAP_IS2_HK_DIP_EQ_SIP] = {123, 1},
++ /* IP4_TCP_UDP (TYPE=100) */
++ [VCAP_IS2_HK_TCP] = {124, 1},
++ [VCAP_IS2_HK_L4_SPORT] = {125, 16},
++ [VCAP_IS2_HK_L4_DPORT] = {141, 16},
++ [VCAP_IS2_HK_L4_RNG] = {157, 8},
++ [VCAP_IS2_HK_L4_SPORT_EQ_DPORT] = {165, 1},
++ [VCAP_IS2_HK_L4_SEQUENCE_EQ0] = {166, 1},
++ [VCAP_IS2_HK_L4_URG] = {167, 1},
++ [VCAP_IS2_HK_L4_ACK] = {168, 1},
++ [VCAP_IS2_HK_L4_PSH] = {169, 1},
++ [VCAP_IS2_HK_L4_RST] = {170, 1},
++ [VCAP_IS2_HK_L4_SYN] = {171, 1},
++ [VCAP_IS2_HK_L4_FIN] = {172, 1},
++ [VCAP_IS2_HK_L4_1588_DOM] = {173, 8},
++ [VCAP_IS2_HK_L4_1588_VER] = {181, 4},
++ /* IP4_OTHER (TYPE=101) */
++ [VCAP_IS2_HK_IP4_L3_PROTO] = {124, 8},
++ [VCAP_IS2_HK_L3_PAYLOAD] = {132, 56},
++ /* IP6_STD (TYPE=110) */
++ [VCAP_IS2_HK_IP6_L3_TTL_GT0] = { 46, 1},
++ [VCAP_IS2_HK_L3_IP6_SIP] = { 47, 128},
++ [VCAP_IS2_HK_IP6_L3_PROTO] = {175, 8},
++ /* OAM (TYPE=111) */
++ [VCAP_IS2_HK_OAM_MEL_FLAGS] = {142, 7},
++ [VCAP_IS2_HK_OAM_VER] = {149, 5},
++ [VCAP_IS2_HK_OAM_OPCODE] = {154, 8},
++ [VCAP_IS2_HK_OAM_FLAGS] = {162, 8},
++ [VCAP_IS2_HK_OAM_MEPID] = {170, 16},
++ [VCAP_IS2_HK_OAM_CCM_CNTS_EQ0] = {186, 1},
++ [VCAP_IS2_HK_OAM_IS_Y1731] = {187, 1},
++};
++
++static const struct vcap_field vsc7514_vcap_is2_actions[] = {
++ [VCAP_IS2_ACT_HIT_ME_ONCE] = { 0, 1},
++ [VCAP_IS2_ACT_CPU_COPY_ENA] = { 1, 1},
++ [VCAP_IS2_ACT_CPU_QU_NUM] = { 2, 3},
++ [VCAP_IS2_ACT_MASK_MODE] = { 5, 2},
++ [VCAP_IS2_ACT_MIRROR_ENA] = { 7, 1},
++ [VCAP_IS2_ACT_LRN_DIS] = { 8, 1},
++ [VCAP_IS2_ACT_POLICE_ENA] = { 9, 1},
++ [VCAP_IS2_ACT_POLICE_IDX] = { 10, 9},
++ [VCAP_IS2_ACT_POLICE_VCAP_ONLY] = { 19, 1},
++ [VCAP_IS2_ACT_PORT_MASK] = { 20, 11},
++ [VCAP_IS2_ACT_REW_OP] = { 31, 9},
++ [VCAP_IS2_ACT_SMAC_REPLACE_ENA] = { 40, 1},
++ [VCAP_IS2_ACT_RSV] = { 41, 2},
++ [VCAP_IS2_ACT_ACL_ID] = { 43, 6},
++ [VCAP_IS2_ACT_HIT_CNT] = { 49, 32},
++};
++
++static const struct vcap_props vsc7514_vcap_props[] = {
++ [VCAP_IS2] = {
++ .tg_width = 2,
++ .sw_count = 4,
++ .entry_count = VSC7514_VCAP_IS2_CNT,
++ .entry_width = VSC7514_VCAP_IS2_ENTRY_WIDTH,
++ .action_count = VSC7514_VCAP_IS2_CNT +
++ VSC7514_VCAP_PORT_CNT + 2,
++ .action_width = 99,
++ .action_type_width = 1,
++ .action_table = {
++ [IS2_ACTION_TYPE_NORMAL] = {
++ .width = 49,
++ .count = 2
++ },
++ [IS2_ACTION_TYPE_SMAC_SIP] = {
++ .width = 6,
++ .count = 4
++ },
++ },
++ .counter_words = 4,
++ .counter_width = 32,
++ },
++};
++
++static struct ptp_clock_info ocelot_ptp_clock_info = {
++ .owner = THIS_MODULE,
++ .name = "ocelot ptp",
++ .max_adj = 0x7fffffff,
++ .n_alarm = 0,
++ .n_ext_ts = 0,
++ .n_per_out = OCELOT_PTP_PINS_NUM,
++ .n_pins = OCELOT_PTP_PINS_NUM,
++ .pps = 0,
++ .gettime64 = ocelot_ptp_gettime64,
++ .settime64 = ocelot_ptp_settime64,
++ .adjtime = ocelot_ptp_adjtime,
++ .adjfine = ocelot_ptp_adjfine,
++ .verify = ocelot_ptp_verify,
++ .enable = ocelot_ptp_enable,
++};
++
++static int mscc_ocelot_probe(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct device_node *ports, *portnp;
++ int err, irq_xtr, irq_ptp_rdy;
++ struct ocelot *ocelot;
++ struct regmap *hsio;
++ unsigned int i;
++
++ struct {
++ enum ocelot_target id;
++ char *name;
++ u8 optional:1;
++ } io_target[] = {
++ { SYS, "sys" },
++ { REW, "rew" },
++ { QSYS, "qsys" },
++ { ANA, "ana" },
++ { QS, "qs" },
++ { S2, "s2" },
++ { PTP, "ptp", 1 },
++ };
++
++ if (!np && !pdev->dev.platform_data)
++ return -ENODEV;
++
++ ocelot = devm_kzalloc(&pdev->dev, sizeof(*ocelot), GFP_KERNEL);
++ if (!ocelot)
++ return -ENOMEM;
++
++ platform_set_drvdata(pdev, ocelot);
++ ocelot->dev = &pdev->dev;
++
++ for (i = 0; i < ARRAY_SIZE(io_target); i++) {
++ struct regmap *target;
++ struct resource *res;
++
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
++ io_target[i].name);
++
++ target = ocelot_regmap_init(ocelot, res);
++ if (IS_ERR(target)) {
++ if (io_target[i].optional) {
++ ocelot->targets[io_target[i].id] = NULL;
++ continue;
++ }
++ return PTR_ERR(target);
++ }
++
++ ocelot->targets[io_target[i].id] = target;
++ }
++
++ hsio = syscon_regmap_lookup_by_compatible("mscc,ocelot-hsio");
++ if (IS_ERR(hsio)) {
++ dev_err(&pdev->dev, "missing hsio syscon\n");
++ return PTR_ERR(hsio);
++ }
++
++ ocelot->targets[HSIO] = hsio;
++
++ err = ocelot_chip_init(ocelot, &ocelot_ops);
++ if (err)
++ return err;
++
++ irq_xtr = platform_get_irq_byname(pdev, "xtr");
++ if (irq_xtr < 0)
++ return -ENODEV;
++
++ err = devm_request_threaded_irq(&pdev->dev, irq_xtr, NULL,
++ ocelot_xtr_irq_handler, IRQF_ONESHOT,
++ "frame extraction", ocelot);
++ if (err)
++ return err;
++
++ irq_ptp_rdy = platform_get_irq_byname(pdev, "ptp_rdy");
++ if (irq_ptp_rdy > 0 && ocelot->targets[PTP]) {
++ err = devm_request_threaded_irq(&pdev->dev, irq_ptp_rdy, NULL,
++ ocelot_ptp_rdy_irq_handler,
++ IRQF_ONESHOT, "ptp ready",
++ ocelot);
++ if (err)
++ return err;
++
++ /* Both the PTP interrupt and the PTP bank are available */
++ ocelot->ptp = 1;
++ }
++
++ ports = of_get_child_by_name(np, "ethernet-ports");
++ if (!ports) {
++ dev_err(&pdev->dev, "no ethernet-ports child node found\n");
++ return -ENODEV;
++ }
++
++ ocelot->num_phys_ports = of_get_child_count(ports);
++
++ ocelot->ports = devm_kcalloc(&pdev->dev, ocelot->num_phys_ports,
++ sizeof(struct ocelot_port *), GFP_KERNEL);
++
++ ocelot->vcap_is2_keys = vsc7514_vcap_is2_keys;
++ ocelot->vcap_is2_actions = vsc7514_vcap_is2_actions;
++ ocelot->vcap = vsc7514_vcap_props;
++
++ ocelot_init(ocelot);
++ if (ocelot->ptp) {
++ err = ocelot_init_timestamp(ocelot, &ocelot_ptp_clock_info);
++ if (err) {
++ dev_err(ocelot->dev,
++ "Timestamp initialization failed\n");
++ ocelot->ptp = 0;
++ }
++ }
++
++ /* No NPI port */
++ ocelot_configure_cpu(ocelot, -1, OCELOT_TAG_PREFIX_NONE,
++ OCELOT_TAG_PREFIX_NONE);
++
++ for_each_available_child_of_node(ports, portnp) {
++ struct ocelot_port_private *priv;
++ struct ocelot_port *ocelot_port;
++ struct device_node *phy_node;
++ phy_interface_t phy_mode;
++ struct phy_device *phy;
++ struct resource *res;
++ struct phy *serdes;
++ void __iomem *regs;
++ char res_name[8];
++ u32 port;
++
++ if (of_property_read_u32(portnp, "reg", &port))
++ continue;
++
++ snprintf(res_name, sizeof(res_name), "port%d", port);
++
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
++ res_name);
++ regs = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(regs))
++ continue;
++
++ phy_node = of_parse_phandle(portnp, "phy-handle", 0);
++ if (!phy_node)
++ continue;
++
++ phy = of_phy_find_device(phy_node);
++ of_node_put(phy_node);
++ if (!phy)
++ continue;
++
++ err = ocelot_probe_port(ocelot, port, regs, phy);
++ if (err) {
++ of_node_put(portnp);
++ goto out_put_ports;
++ }
++
++ ocelot_port = ocelot->ports[port];
++ priv = container_of(ocelot_port, struct ocelot_port_private,
++ port);
++
++ of_get_phy_mode(portnp, &phy_mode);
++
++ ocelot_port->phy_mode = phy_mode;
++
++ switch (ocelot_port->phy_mode) {
++ case PHY_INTERFACE_MODE_NA:
++ continue;
++ case PHY_INTERFACE_MODE_SGMII:
++ break;
++ case PHY_INTERFACE_MODE_QSGMII:
++ /* Ensure clock signals and speed is set on all
++ * QSGMII links
++ */
++ ocelot_port_writel(ocelot_port,
++ DEV_CLOCK_CFG_LINK_SPEED
++ (OCELOT_SPEED_1000),
++ DEV_CLOCK_CFG);
++ break;
++ default:
++ dev_err(ocelot->dev,
++ "invalid phy mode for port%d, (Q)SGMII only\n",
++ port);
++ of_node_put(portnp);
++ err = -EINVAL;
++ goto out_put_ports;
++ }
++
++ serdes = devm_of_phy_get(ocelot->dev, portnp, NULL);
++ if (IS_ERR(serdes)) {
++ err = PTR_ERR(serdes);
++ if (err == -EPROBE_DEFER)
++ dev_dbg(ocelot->dev, "deferring probe\n");
++ else
++ dev_err(ocelot->dev,
++ "missing SerDes phys for port%d\n",
++ port);
++
++ of_node_put(portnp);
++ goto out_put_ports;
++ }
++
++ priv->serdes = serdes;
++ }
++
++ register_netdevice_notifier(&ocelot_netdevice_nb);
++ register_switchdev_notifier(&ocelot_switchdev_nb);
++ register_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb);
++
++ dev_info(&pdev->dev, "Ocelot switch probed\n");
++
++out_put_ports:
++ of_node_put(ports);
++ return err;
++}
++
++static int mscc_ocelot_remove(struct platform_device *pdev)
++{
++ struct ocelot *ocelot = platform_get_drvdata(pdev);
++
++ ocelot_deinit_timestamp(ocelot);
++ ocelot_deinit(ocelot);
++ unregister_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb);
++ unregister_switchdev_notifier(&ocelot_switchdev_nb);
++ unregister_netdevice_notifier(&ocelot_netdevice_nb);
++
++ return 0;
++}
++
++static struct platform_driver mscc_ocelot_driver = {
++ .probe = mscc_ocelot_probe,
++ .remove = mscc_ocelot_remove,
++ .driver = {
++ .name = "ocelot-switch",
++ .of_match_table = mscc_ocelot_match,
++ },
++};
++
++module_platform_driver(mscc_ocelot_driver);
++
++MODULE_DESCRIPTION("Microsemi Ocelot switch driver");
++MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>");
++MODULE_LICENSE("Dual MIT/GPL");
+diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
+index b660ddbe40251..fe173ea894e2c 100644
+--- a/drivers/net/ethernet/realtek/r8169_main.c
++++ b/drivers/net/ethernet/realtek/r8169_main.c
+@@ -2113,11 +2113,18 @@ static void rtl_release_firmware(struct rtl8169_private *tp)
+
+ void r8169_apply_firmware(struct rtl8169_private *tp)
+ {
++ int val;
++
+ /* TODO: release firmware if rtl_fw_write_firmware signals failure. */
+ if (tp->rtl_fw) {
+ rtl_fw_write_firmware(tp, tp->rtl_fw);
+ /* At least one firmware doesn't reset tp->ocp_base. */
+ tp->ocp_base = OCP_STD_PHY_BASE;
++
++ /* PHY soft reset may still be in progress */
++ phy_read_poll_timeout(tp->phydev, MII_BMCR, val,
++ !(val & BMCR_RESET),
++ 50000, 600000, true);
+ }
+ }
+
+@@ -2951,7 +2958,7 @@ static void rtl_hw_start_8168f_1(struct rtl8169_private *tp)
+ { 0x08, 0x0001, 0x0002 },
+ { 0x09, 0x0000, 0x0080 },
+ { 0x19, 0x0000, 0x0224 },
+- { 0x00, 0x0000, 0x0004 },
++ { 0x00, 0x0000, 0x0008 },
+ { 0x0c, 0x3df0, 0x0200 },
+ };
+
+@@ -2968,7 +2975,7 @@ static void rtl_hw_start_8411(struct rtl8169_private *tp)
+ { 0x06, 0x00c0, 0x0020 },
+ { 0x0f, 0xffff, 0x5200 },
+ { 0x19, 0x0000, 0x0224 },
+- { 0x00, 0x0000, 0x0004 },
++ { 0x00, 0x0000, 0x0008 },
+ { 0x0c, 0x3df0, 0x0200 },
+ };
+
+diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
+index df89d09b253e2..99f7aae102ce1 100644
+--- a/drivers/net/ethernet/renesas/ravb_main.c
++++ b/drivers/net/ethernet/renesas/ravb_main.c
+@@ -1342,51 +1342,6 @@ static inline int ravb_hook_irq(unsigned int irq, irq_handler_t handler,
+ return error;
+ }
+
+-/* MDIO bus init function */
+-static int ravb_mdio_init(struct ravb_private *priv)
+-{
+- struct platform_device *pdev = priv->pdev;
+- struct device *dev = &pdev->dev;
+- int error;
+-
+- /* Bitbang init */
+- priv->mdiobb.ops = &bb_ops;
+-
+- /* MII controller setting */
+- priv->mii_bus = alloc_mdio_bitbang(&priv->mdiobb);
+- if (!priv->mii_bus)
+- return -ENOMEM;
+-
+- /* Hook up MII support for ethtool */
+- priv->mii_bus->name = "ravb_mii";
+- priv->mii_bus->parent = dev;
+- snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+- pdev->name, pdev->id);
+-
+- /* Register MDIO bus */
+- error = of_mdiobus_register(priv->mii_bus, dev->of_node);
+- if (error)
+- goto out_free_bus;
+-
+- return 0;
+-
+-out_free_bus:
+- free_mdio_bitbang(priv->mii_bus);
+- return error;
+-}
+-
+-/* MDIO bus release function */
+-static int ravb_mdio_release(struct ravb_private *priv)
+-{
+- /* Unregister mdio bus */
+- mdiobus_unregister(priv->mii_bus);
+-
+- /* Free bitbang info */
+- free_mdio_bitbang(priv->mii_bus);
+-
+- return 0;
+-}
+-
+ /* Network device open function for Ethernet AVB */
+ static int ravb_open(struct net_device *ndev)
+ {
+@@ -1395,13 +1350,6 @@ static int ravb_open(struct net_device *ndev)
+ struct device *dev = &pdev->dev;
+ int error;
+
+- /* MDIO bus init */
+- error = ravb_mdio_init(priv);
+- if (error) {
+- netdev_err(ndev, "failed to initialize MDIO\n");
+- return error;
+- }
+-
+ napi_enable(&priv->napi[RAVB_BE]);
+ napi_enable(&priv->napi[RAVB_NC]);
+
+@@ -1479,7 +1427,6 @@ out_free_irq:
+ out_napi_off:
+ napi_disable(&priv->napi[RAVB_NC]);
+ napi_disable(&priv->napi[RAVB_BE]);
+- ravb_mdio_release(priv);
+ return error;
+ }
+
+@@ -1789,8 +1736,6 @@ static int ravb_close(struct net_device *ndev)
+ ravb_ring_free(ndev, RAVB_BE);
+ ravb_ring_free(ndev, RAVB_NC);
+
+- ravb_mdio_release(priv);
+-
+ return 0;
+ }
+
+@@ -1942,6 +1887,51 @@ static const struct net_device_ops ravb_netdev_ops = {
+ .ndo_set_features = ravb_set_features,
+ };
+
++/* MDIO bus init function */
++static int ravb_mdio_init(struct ravb_private *priv)
++{
++ struct platform_device *pdev = priv->pdev;
++ struct device *dev = &pdev->dev;
++ int error;
++
++ /* Bitbang init */
++ priv->mdiobb.ops = &bb_ops;
++
++ /* MII controller setting */
++ priv->mii_bus = alloc_mdio_bitbang(&priv->mdiobb);
++ if (!priv->mii_bus)
++ return -ENOMEM;
++
++ /* Hook up MII support for ethtool */
++ priv->mii_bus->name = "ravb_mii";
++ priv->mii_bus->parent = dev;
++ snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
++ pdev->name, pdev->id);
++
++ /* Register MDIO bus */
++ error = of_mdiobus_register(priv->mii_bus, dev->of_node);
++ if (error)
++ goto out_free_bus;
++
++ return 0;
++
++out_free_bus:
++ free_mdio_bitbang(priv->mii_bus);
++ return error;
++}
++
++/* MDIO bus release function */
++static int ravb_mdio_release(struct ravb_private *priv)
++{
++ /* Unregister mdio bus */
++ mdiobus_unregister(priv->mii_bus);
++
++ /* Free bitbang info */
++ free_mdio_bitbang(priv->mii_bus);
++
++ return 0;
++}
++
+ static const struct of_device_id ravb_match_table[] = {
+ { .compatible = "renesas,etheravb-r8a7790", .data = (void *)RCAR_GEN2 },
+ { .compatible = "renesas,etheravb-r8a7794", .data = (void *)RCAR_GEN2 },
+@@ -2184,6 +2174,13 @@ static int ravb_probe(struct platform_device *pdev)
+ eth_hw_addr_random(ndev);
+ }
+
++ /* MDIO bus init */
++ error = ravb_mdio_init(priv);
++ if (error) {
++ dev_err(&pdev->dev, "failed to initialize MDIO\n");
++ goto out_dma_free;
++ }
++
+ netif_napi_add(ndev, &priv->napi[RAVB_BE], ravb_poll, 64);
+ netif_napi_add(ndev, &priv->napi[RAVB_NC], ravb_poll, 64);
+
+@@ -2205,6 +2202,8 @@ static int ravb_probe(struct platform_device *pdev)
+ out_napi_del:
+ netif_napi_del(&priv->napi[RAVB_NC]);
+ netif_napi_del(&priv->napi[RAVB_BE]);
++ ravb_mdio_release(priv);
++out_dma_free:
+ dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat,
+ priv->desc_bat_dma);
+
+@@ -2236,6 +2235,7 @@ static int ravb_remove(struct platform_device *pdev)
+ unregister_netdev(ndev);
+ netif_napi_del(&priv->napi[RAVB_NC]);
+ netif_napi_del(&priv->napi[RAVB_BE]);
++ ravb_mdio_release(priv);
+ pm_runtime_disable(&pdev->dev);
+ free_netdev(ndev);
+ platform_set_drvdata(pdev, NULL);
+diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
+index 2ac9dfb3462c6..9e6d60e75f85d 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
+@@ -653,7 +653,6 @@ static void intel_eth_pci_remove(struct pci_dev *pdev)
+
+ pci_free_irq_vectors(pdev);
+
+- clk_disable_unprepare(priv->plat->stmmac_clk);
+ clk_unregister_fixed_rate(priv->plat->stmmac_clk);
+
+ pcim_iounmap_regions(pdev, BIT(0));
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+index 9c02fc754bf1b..545696971f65e 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+@@ -203,6 +203,8 @@ struct stmmac_priv {
+ int eee_enabled;
+ int eee_active;
+ int tx_lpi_timer;
++ int tx_lpi_enabled;
++ int eee_tw_timer;
+ unsigned int mode;
+ unsigned int chain_mode;
+ int extend_desc;
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+index eae11c5850251..b82c6715f95f3 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+@@ -652,6 +652,7 @@ static int stmmac_ethtool_op_get_eee(struct net_device *dev,
+ edata->eee_enabled = priv->eee_enabled;
+ edata->eee_active = priv->eee_active;
+ edata->tx_lpi_timer = priv->tx_lpi_timer;
++ edata->tx_lpi_enabled = priv->tx_lpi_enabled;
+
+ return phylink_ethtool_get_eee(priv->phylink, edata);
+ }
+@@ -662,24 +663,26 @@ static int stmmac_ethtool_op_set_eee(struct net_device *dev,
+ struct stmmac_priv *priv = netdev_priv(dev);
+ int ret;
+
+- if (!edata->eee_enabled) {
++ if (!priv->dma_cap.eee)
++ return -EOPNOTSUPP;
++
++ if (priv->tx_lpi_enabled != edata->tx_lpi_enabled)
++ netdev_warn(priv->dev,
++ "Setting EEE tx-lpi is not supported\n");
++
++ if (!edata->eee_enabled)
+ stmmac_disable_eee_mode(priv);
+- } else {
+- /* We are asking for enabling the EEE but it is safe
+- * to verify all by invoking the eee_init function.
+- * In case of failure it will return an error.
+- */
+- edata->eee_enabled = stmmac_eee_init(priv);
+- if (!edata->eee_enabled)
+- return -EOPNOTSUPP;
+- }
+
+ ret = phylink_ethtool_set_eee(priv->phylink, edata);
+ if (ret)
+ return ret;
+
+- priv->eee_enabled = edata->eee_enabled;
+- priv->tx_lpi_timer = edata->tx_lpi_timer;
++ if (edata->eee_enabled &&
++ priv->tx_lpi_timer != edata->tx_lpi_timer) {
++ priv->tx_lpi_timer = edata->tx_lpi_timer;
++ stmmac_eee_init(priv);
++ }
++
+ return 0;
+ }
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index 73677c3b33b65..73465e5f5a417 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -94,7 +94,7 @@ static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
+ static int eee_timer = STMMAC_DEFAULT_LPI_TIMER;
+ module_param(eee_timer, int, 0644);
+ MODULE_PARM_DESC(eee_timer, "LPI tx expiration time in msec");
+-#define STMMAC_LPI_T(x) (jiffies + msecs_to_jiffies(x))
++#define STMMAC_LPI_T(x) (jiffies + usecs_to_jiffies(x))
+
+ /* By default the driver will use the ring mode to manage tx and rx descriptors,
+ * but allow user to force to use the chain instead of the ring
+@@ -370,7 +370,7 @@ static void stmmac_eee_ctrl_timer(struct timer_list *t)
+ struct stmmac_priv *priv = from_timer(priv, t, eee_ctrl_timer);
+
+ stmmac_enable_eee_mode(priv);
+- mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(eee_timer));
++ mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(priv->tx_lpi_timer));
+ }
+
+ /**
+@@ -383,7 +383,7 @@ static void stmmac_eee_ctrl_timer(struct timer_list *t)
+ */
+ bool stmmac_eee_init(struct stmmac_priv *priv)
+ {
+- int tx_lpi_timer = priv->tx_lpi_timer;
++ int eee_tw_timer = priv->eee_tw_timer;
+
+ /* Using PCS we cannot dial with the phy registers at this stage
+ * so we do not support extra feature like EEE.
+@@ -403,7 +403,7 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
+ if (priv->eee_enabled) {
+ netdev_dbg(priv->dev, "disable EEE\n");
+ del_timer_sync(&priv->eee_ctrl_timer);
+- stmmac_set_eee_timer(priv, priv->hw, 0, tx_lpi_timer);
++ stmmac_set_eee_timer(priv, priv->hw, 0, eee_tw_timer);
+ }
+ mutex_unlock(&priv->lock);
+ return false;
+@@ -411,11 +411,12 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
+
+ if (priv->eee_active && !priv->eee_enabled) {
+ timer_setup(&priv->eee_ctrl_timer, stmmac_eee_ctrl_timer, 0);
+- mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(eee_timer));
+ stmmac_set_eee_timer(priv, priv->hw, STMMAC_DEFAULT_LIT_LS,
+- tx_lpi_timer);
++ eee_tw_timer);
+ }
+
++ mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(priv->tx_lpi_timer));
++
+ mutex_unlock(&priv->lock);
+ netdev_dbg(priv->dev, "Energy-Efficient Ethernet initialized\n");
+ return true;
+@@ -930,6 +931,7 @@ static void stmmac_mac_link_down(struct phylink_config *config,
+
+ stmmac_mac_set(priv, priv->ioaddr, false);
+ priv->eee_active = false;
++ priv->tx_lpi_enabled = false;
+ stmmac_eee_init(priv);
+ stmmac_set_eee_pls(priv, priv->hw, false);
+ }
+@@ -1027,6 +1029,7 @@ static void stmmac_mac_link_up(struct phylink_config *config,
+ if (phy && priv->dma_cap.eee) {
+ priv->eee_active = phy_init_eee(phy, 1) >= 0;
+ priv->eee_enabled = stmmac_eee_init(priv);
++ priv->tx_lpi_enabled = priv->eee_enabled;
+ stmmac_set_eee_pls(priv, priv->hw, true);
+ }
+ }
+@@ -2057,7 +2060,7 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
+
+ if ((priv->eee_enabled) && (!priv->tx_path_in_lpi_mode)) {
+ stmmac_enable_eee_mode(priv);
+- mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(eee_timer));
++ mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(priv->tx_lpi_timer));
+ }
+
+ /* We still have pending packets, let's call for a new scheduling */
+@@ -2690,7 +2693,11 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
+ netdev_warn(priv->dev, "PTP init failed\n");
+ }
+
+- priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS;
++ priv->eee_tw_timer = STMMAC_DEFAULT_TWT_LS;
++
++ /* Convert the timer from msec to usec */
++ if (!priv->tx_lpi_timer)
++ priv->tx_lpi_timer = eee_timer * 1000;
+
+ if (priv->use_riwt) {
+ if (!priv->rx_riwt)
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index 9159846b8b938..787ac2c8e74eb 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -1077,6 +1077,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
+ struct macsec_rx_sa *rx_sa;
+ struct macsec_rxh_data *rxd;
+ struct macsec_dev *macsec;
++ unsigned int len;
+ sci_t sci;
+ u32 hdr_pn;
+ bool cbit;
+@@ -1232,9 +1233,10 @@ deliver:
+ macsec_rxsc_put(rx_sc);
+
+ skb_orphan(skb);
++ len = skb->len;
+ ret = gro_cells_receive(&macsec->gro_cells, skb);
+ if (ret == NET_RX_SUCCESS)
+- count_rx(dev, skb->len);
++ count_rx(dev, len);
+ else
+ macsec->secy.netdev->stats.rx_dropped++;
+
+diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
+index e351d65533aa8..06146ae4c6d8d 100644
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -217,6 +217,7 @@ config MDIO_THUNDER
+ depends on 64BIT
+ depends on PCI
+ select MDIO_CAVIUM
++ select MDIO_DEVRES
+ help
+ This driver supports the MDIO interfaces found on Cavium
+ ThunderX SoCs when the MDIO bus device appears as a PCI
+diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
+index c7229d022a27b..48ba757046cea 100644
+--- a/drivers/net/phy/realtek.c
++++ b/drivers/net/phy/realtek.c
+@@ -1,6 +1,5 @@
+ // SPDX-License-Identifier: GPL-2.0+
+-/*
+- * drivers/net/phy/realtek.c
++/* drivers/net/phy/realtek.c
+ *
+ * Driver for Realtek PHYs
+ *
+@@ -32,9 +31,9 @@
+ #define RTL8211F_TX_DELAY BIT(8)
+ #define RTL8211F_RX_DELAY BIT(3)
+
+-#define RTL8211E_TX_DELAY BIT(1)
+-#define RTL8211E_RX_DELAY BIT(2)
+-#define RTL8211E_MODE_MII_GMII BIT(3)
++#define RTL8211E_CTRL_DELAY BIT(13)
++#define RTL8211E_TX_DELAY BIT(12)
++#define RTL8211E_RX_DELAY BIT(11)
+
+ #define RTL8201F_ISR 0x1e
+ #define RTL8201F_IER 0x13
+@@ -246,16 +245,16 @@ static int rtl8211e_config_init(struct phy_device *phydev)
+ /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */
+ switch (phydev->interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+- val = 0;
++ val = RTL8211E_CTRL_DELAY | 0;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_ID:
+- val = RTL8211E_TX_DELAY | RTL8211E_RX_DELAY;
++ val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+- val = RTL8211E_RX_DELAY;
++ val = RTL8211E_CTRL_DELAY | RTL8211E_RX_DELAY;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+- val = RTL8211E_TX_DELAY;
++ val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY;
+ break;
+ default: /* the rest of the modes imply leaving delays as is. */
+ return 0;
+@@ -263,11 +262,12 @@ static int rtl8211e_config_init(struct phy_device *phydev)
+
+ /* According to a sample driver there is a 0x1c config register on the
+ * 0xa4 extension page (0x7) layout. It can be used to disable/enable
+- * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins. It can
+- * also be used to customize the whole configuration register:
+- * 8:6 = PHY Address, 5:4 = Auto-Negotiation, 3 = Interface Mode Select,
+- * 2 = RX Delay, 1 = TX Delay, 0 = SELRGV (see original PHY datasheet
+- * for details).
++ * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins.
++ * The configuration register definition:
++ * 14 = reserved
++ * 13 = Force Tx RX Delay controlled by bit12 bit11,
++ * 12 = RX Delay, 11 = TX Delay
++ * 10:0 = Test && debug settings reserved by realtek
+ */
+ oldpage = phy_select_page(phydev, 0x7);
+ if (oldpage < 0)
+@@ -277,7 +277,8 @@ static int rtl8211e_config_init(struct phy_device *phydev)
+ if (ret)
+ goto err_restore_page;
+
+- ret = __phy_modify(phydev, 0x1c, RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
++ ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY
++ | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
+ val);
+
+ err_restore_page:
+diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
+index 8c1e02752ff61..bcc4a4c011f1f 100644
+--- a/drivers/net/team/team.c
++++ b/drivers/net/team/team.c
+@@ -287,7 +287,7 @@ inst_rollback:
+ for (i--; i >= 0; i--)
+ __team_option_inst_del_option(team, dst_opts[i]);
+
+- i = option_count - 1;
++ i = option_count;
+ alloc_rollback:
+ for (i--; i >= 0; i--)
+ kfree(dst_opts[i]);
+@@ -2112,6 +2112,7 @@ static void team_setup_by_port(struct net_device *dev,
+ dev->header_ops = port_dev->header_ops;
+ dev->type = port_dev->type;
+ dev->hard_header_len = port_dev->hard_header_len;
++ dev->needed_headroom = port_dev->needed_headroom;
+ dev->addr_len = port_dev->addr_len;
+ dev->mtu = port_dev->mtu;
+ memcpy(dev->broadcast, port_dev->broadcast, port_dev->addr_len);
+diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
+index a38e868e44d46..f0ef3706aad96 100644
+--- a/drivers/net/usb/ax88179_178a.c
++++ b/drivers/net/usb/ax88179_178a.c
+@@ -1823,6 +1823,7 @@ static const struct driver_info belkin_info = {
+ .status = ax88179_status,
+ .link_reset = ax88179_link_reset,
+ .reset = ax88179_reset,
++ .stop = ax88179_stop,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+ .rx_fixup = ax88179_rx_fixup,
+ .tx_fixup = ax88179_tx_fixup,
+diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
+index e7c630d375899..63a4da0b2d6dd 100644
+--- a/drivers/net/usb/rtl8150.c
++++ b/drivers/net/usb/rtl8150.c
+@@ -274,12 +274,20 @@ static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg)
+ return 1;
+ }
+
+-static inline void set_ethernet_addr(rtl8150_t * dev)
++static void set_ethernet_addr(rtl8150_t *dev)
+ {
+- u8 node_id[6];
++ u8 node_id[ETH_ALEN];
++ int ret;
++
++ ret = get_registers(dev, IDR, sizeof(node_id), node_id);
+
+- get_registers(dev, IDR, sizeof(node_id), node_id);
+- memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));
++ if (ret == sizeof(node_id)) {
++ ether_addr_copy(dev->netdev->dev_addr, node_id);
++ } else {
++ eth_hw_addr_random(dev->netdev);
++ netdev_notice(dev->netdev, "Assigned a random MAC address: %pM\n",
++ dev->netdev->dev_addr);
++ }
+ }
+
+ static int rtl8150_set_mac_address(struct net_device *netdev, void *p)
+diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
+index ba38765dc4905..c34927b1d806e 100644
+--- a/drivers/net/virtio_net.c
++++ b/drivers/net/virtio_net.c
+@@ -63,6 +63,11 @@ static const unsigned long guest_offloads[] = {
+ VIRTIO_NET_F_GUEST_CSUM
+ };
+
++#define GUEST_OFFLOAD_LRO_MASK ((1ULL << VIRTIO_NET_F_GUEST_TSO4) | \
++ (1ULL << VIRTIO_NET_F_GUEST_TSO6) | \
++ (1ULL << VIRTIO_NET_F_GUEST_ECN) | \
++ (1ULL << VIRTIO_NET_F_GUEST_UFO))
++
+ struct virtnet_stat_desc {
+ char desc[ETH_GSTRING_LEN];
+ size_t offset;
+@@ -2547,7 +2552,8 @@ static int virtnet_set_features(struct net_device *dev,
+ if (features & NETIF_F_LRO)
+ offloads = vi->guest_offloads_capable;
+ else
+- offloads = 0;
++ offloads = vi->guest_offloads_capable &
++ ~GUEST_OFFLOAD_LRO_MASK;
+
+ err = virtnet_set_guest_offloads(vi, offloads);
+ if (err)
+diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
+index 2818015324b8b..336504b7531d9 100644
+--- a/drivers/net/vmxnet3/vmxnet3_drv.c
++++ b/drivers/net/vmxnet3/vmxnet3_drv.c
+@@ -1032,7 +1032,6 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
+ /* Use temporary descriptor to avoid touching bits multiple times */
+ union Vmxnet3_GenericDesc tempTxDesc;
+ #endif
+- struct udphdr *udph;
+
+ count = txd_estimate(skb);
+
+@@ -1135,8 +1134,7 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
+ gdesc->txd.om = VMXNET3_OM_ENCAP;
+ gdesc->txd.msscof = ctx.mss;
+
+- udph = udp_hdr(skb);
+- if (udph->check)
++ if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)
+ gdesc->txd.oco = 1;
+ } else {
+ gdesc->txd.hlen = ctx.l4_offset + ctx.l4_hdr_size;
+@@ -3371,6 +3369,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
+ .ndo_change_mtu = vmxnet3_change_mtu,
+ .ndo_fix_features = vmxnet3_fix_features,
+ .ndo_set_features = vmxnet3_set_features,
++ .ndo_features_check = vmxnet3_features_check,
+ .ndo_get_stats64 = vmxnet3_get_stats64,
+ .ndo_tx_timeout = vmxnet3_tx_timeout,
+ .ndo_set_rx_mode = vmxnet3_set_mc,
+diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
+index def27afa1c69f..3586677920046 100644
+--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
++++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
+@@ -267,6 +267,34 @@ netdev_features_t vmxnet3_fix_features(struct net_device *netdev,
+ return features;
+ }
+
++netdev_features_t vmxnet3_features_check(struct sk_buff *skb,
++ struct net_device *netdev,
++ netdev_features_t features)
++{
++ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
++
++ /* Validate if the tunneled packet is being offloaded by the device */
++ if (VMXNET3_VERSION_GE_4(adapter) &&
++ skb->encapsulation && skb->ip_summed == CHECKSUM_PARTIAL) {
++ u8 l4_proto = 0;
++
++ switch (vlan_get_protocol(skb)) {
++ case htons(ETH_P_IP):
++ l4_proto = ip_hdr(skb)->protocol;
++ break;
++ case htons(ETH_P_IPV6):
++ l4_proto = ipv6_hdr(skb)->nexthdr;
++ break;
++ default:
++ return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
++ }
++
++ if (l4_proto != IPPROTO_UDP)
++ return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
++ }
++ return features;
++}
++
+ static void vmxnet3_enable_encap_offloads(struct net_device *netdev)
+ {
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
+index 5d2b062215a27..d958b92c94299 100644
+--- a/drivers/net/vmxnet3/vmxnet3_int.h
++++ b/drivers/net/vmxnet3/vmxnet3_int.h
+@@ -470,6 +470,10 @@ vmxnet3_rq_destroy_all(struct vmxnet3_adapter *adapter);
+ netdev_features_t
+ vmxnet3_fix_features(struct net_device *netdev, netdev_features_t features);
+
++netdev_features_t
++vmxnet3_features_check(struct sk_buff *skb,
++ struct net_device *netdev, netdev_features_t features);
++
+ int
+ vmxnet3_set_features(struct net_device *netdev, netdev_features_t features);
+
+diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
+index 69165a8f7c1f0..a9d5682cdea54 100644
+--- a/drivers/nvme/host/core.c
++++ b/drivers/nvme/host/core.c
+@@ -3061,8 +3061,10 @@ static int nvme_dev_open(struct inode *inode, struct file *file)
+ }
+
+ nvme_get_ctrl(ctrl);
+- if (!try_module_get(ctrl->ops->module))
++ if (!try_module_get(ctrl->ops->module)) {
++ nvme_put_ctrl(ctrl);
+ return -EINVAL;
++ }
+
+ file->private_data = ctrl;
+ return 0;
+diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
+index 24467eea73999..9b3827a6f3a39 100644
+--- a/drivers/nvme/host/tcp.c
++++ b/drivers/nvme/host/tcp.c
+@@ -889,12 +889,11 @@ static int nvme_tcp_try_send_data(struct nvme_tcp_request *req)
+ else
+ flags |= MSG_MORE | MSG_SENDPAGE_NOTLAST;
+
+- /* can't zcopy slab pages */
+- if (unlikely(PageSlab(page))) {
+- ret = sock_no_sendpage(queue->sock, page, offset, len,
++ if (sendpage_ok(page)) {
++ ret = kernel_sendpage(queue->sock, page, offset, len,
+ flags);
+ } else {
+- ret = kernel_sendpage(queue->sock, page, offset, len,
++ ret = sock_no_sendpage(queue->sock, page, offset, len,
+ flags);
+ }
+ if (ret <= 0)
+diff --git a/drivers/platform/olpc/olpc-ec.c b/drivers/platform/olpc/olpc-ec.c
+index 190e4a6186ef7..f64b82824db28 100644
+--- a/drivers/platform/olpc/olpc-ec.c
++++ b/drivers/platform/olpc/olpc-ec.c
+@@ -439,7 +439,9 @@ static int olpc_ec_probe(struct platform_device *pdev)
+ &config);
+ if (IS_ERR(ec->dcon_rdev)) {
+ dev_err(&pdev->dev, "failed to register DCON regulator\n");
+- return PTR_ERR(ec->dcon_rdev);
++ err = PTR_ERR(ec->dcon_rdev);
++ kfree(ec);
++ return err;
+ }
+
+ ec->dbgfs_dir = olpc_ec_setup_debugfs();
+diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
+index 0581a54cf562f..a5ad36083b671 100644
+--- a/drivers/platform/x86/Kconfig
++++ b/drivers/platform/x86/Kconfig
+@@ -469,6 +469,7 @@ config FUJITSU_LAPTOP
+ depends on BACKLIGHT_CLASS_DEVICE
+ depends on ACPI_VIDEO || ACPI_VIDEO = n
+ select INPUT_SPARSEKMAP
++ select NEW_LEDS
+ select LEDS_CLASS
+ help
+ This is a driver for laptops built by Fujitsu:
+@@ -1091,6 +1092,7 @@ config LG_LAPTOP
+ depends on ACPI_WMI
+ depends on INPUT
+ select INPUT_SPARSEKMAP
++ select NEW_LEDS
+ select LEDS_CLASS
+ help
+ This driver adds support for hotkeys as well as control of keyboard
+diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
+index 6c42f73c1dfd3..805ce604dee6a 100644
+--- a/drivers/platform/x86/asus-nb-wmi.c
++++ b/drivers/platform/x86/asus-nb-wmi.c
+@@ -120,6 +120,10 @@ static struct quirk_entry quirk_asus_ga502i = {
+ .wmi_backlight_set_devstate = true,
+ };
+
++static struct quirk_entry quirk_asus_use_kbd_dock_devid = {
++ .use_kbd_dock_devid = true,
++};
++
+ static int dmi_matched(const struct dmi_system_id *dmi)
+ {
+ pr_info("Identified laptop model '%s'\n", dmi->ident);
+@@ -493,6 +497,34 @@ static const struct dmi_system_id asus_quirks[] = {
+ },
+ .driver_data = &quirk_asus_ga502i,
+ },
++ {
++ .callback = dmi_matched,
++ .ident = "Asus Transformer T100TA / T100HA / T100CHI",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++ /* Match *T100* */
++ DMI_MATCH(DMI_PRODUCT_NAME, "T100"),
++ },
++ .driver_data = &quirk_asus_use_kbd_dock_devid,
++ },
++ {
++ .callback = dmi_matched,
++ .ident = "Asus Transformer T101HA",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++ DMI_MATCH(DMI_PRODUCT_NAME, "T101HA"),
++ },
++ .driver_data = &quirk_asus_use_kbd_dock_devid,
++ },
++ {
++ .callback = dmi_matched,
++ .ident = "Asus Transformer T200TA",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++ DMI_MATCH(DMI_PRODUCT_NAME, "T200TA"),
++ },
++ .driver_data = &quirk_asus_use_kbd_dock_devid,
++ },
+ {},
+ };
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index 8f4acdc06b134..ae6289d37faf6 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -365,12 +365,14 @@ static int asus_wmi_input_init(struct asus_wmi *asus)
+ if (err)
+ goto err_free_dev;
+
+- result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_KBD_DOCK);
+- if (result >= 0) {
+- input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
+- input_report_switch(asus->inputdev, SW_TABLET_MODE, !result);
+- } else if (result != -ENODEV) {
+- pr_err("Error checking for keyboard-dock: %d\n", result);
++ if (asus->driver->quirks->use_kbd_dock_devid) {
++ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_KBD_DOCK);
++ if (result >= 0) {
++ input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
++ input_report_switch(asus->inputdev, SW_TABLET_MODE, !result);
++ } else if (result != -ENODEV) {
++ pr_err("Error checking for keyboard-dock: %d\n", result);
++ }
+ }
+
+ err = input_register_device(asus->inputdev);
+@@ -2114,7 +2116,7 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
+ return;
+ }
+
+- if (code == NOTIFY_KBD_DOCK_CHANGE) {
++ if (asus->driver->quirks->use_kbd_dock_devid && code == NOTIFY_KBD_DOCK_CHANGE) {
+ result = asus_wmi_get_devstate_simple(asus,
+ ASUS_WMI_DEVID_KBD_DOCK);
+ if (result >= 0) {
+diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h
+index 4f31b68642a08..1a95c172f94b0 100644
+--- a/drivers/platform/x86/asus-wmi.h
++++ b/drivers/platform/x86/asus-wmi.h
+@@ -33,6 +33,7 @@ struct quirk_entry {
+ bool wmi_backlight_native;
+ bool wmi_backlight_set_devstate;
+ bool wmi_force_als_set;
++ bool use_kbd_dock_devid;
+ int wapf;
+ /*
+ * For machines with AMD graphic chips, it will send out WMI event
+diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c
+index e85d8e58320c1..663197fecb20d 100644
+--- a/drivers/platform/x86/intel-vbtn.c
++++ b/drivers/platform/x86/intel-vbtn.c
+@@ -15,9 +15,13 @@
+ #include <linux/platform_device.h>
+ #include <linux/suspend.h>
+
++/* Returned when NOT in tablet mode on some HP Stream x360 11 models */
++#define VGBS_TABLET_MODE_FLAG_ALT 0x10
+ /* When NOT in tablet mode, VGBS returns with the flag 0x40 */
+-#define TABLET_MODE_FLAG 0x40
+-#define DOCK_MODE_FLAG 0x80
++#define VGBS_TABLET_MODE_FLAG 0x40
++#define VGBS_DOCK_MODE_FLAG 0x80
++
++#define VGBS_TABLET_MODE_FLAGS (VGBS_TABLET_MODE_FLAG | VGBS_TABLET_MODE_FLAG_ALT)
+
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("AceLan Kao");
+@@ -72,9 +76,9 @@ static void detect_tablet_mode(struct platform_device *device)
+ if (ACPI_FAILURE(status))
+ return;
+
+- m = !(vgbs & TABLET_MODE_FLAG);
++ m = !(vgbs & VGBS_TABLET_MODE_FLAGS);
+ input_report_switch(priv->input_dev, SW_TABLET_MODE, m);
+- m = (vgbs & DOCK_MODE_FLAG) ? 1 : 0;
++ m = (vgbs & VGBS_DOCK_MODE_FLAG) ? 1 : 0;
+ input_report_switch(priv->input_dev, SW_DOCK, m);
+ }
+
+@@ -167,20 +171,54 @@ static bool intel_vbtn_has_buttons(acpi_handle handle)
+ return ACPI_SUCCESS(status);
+ }
+
++/*
++ * There are several laptops (non 2-in-1) models out there which support VGBS,
++ * but simply always return 0, which we translate to SW_TABLET_MODE=1. This in
++ * turn causes userspace (libinput) to suppress events from the builtin
++ * keyboard and touchpad, making the laptop essentially unusable.
++ *
++ * Since the problem of wrongly reporting SW_TABLET_MODE=1 in combination
++ * with libinput, leads to a non-usable system. Where as OTOH many people will
++ * not even notice when SW_TABLET_MODE is not being reported, a DMI based allow
++ * list is used here. This list mainly matches on the chassis-type of 2-in-1s.
++ *
++ * There are also some 2-in-1s which use the intel-vbtn ACPI interface to report
++ * SW_TABLET_MODE with a chassis-type of 8 ("Portable") or 10 ("Notebook"),
++ * these are matched on a per model basis, since many normal laptops with a
++ * possible broken VGBS ACPI-method also use these chassis-types.
++ */
++static const struct dmi_system_id dmi_switches_allow_list[] = {
++ {
++ .matches = {
++ DMI_EXACT_MATCH(DMI_CHASSIS_TYPE, "31" /* Convertible */),
++ },
++ },
++ {
++ .matches = {
++ DMI_EXACT_MATCH(DMI_CHASSIS_TYPE, "32" /* Detachable */),
++ },
++ },
++ {
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
++ DMI_MATCH(DMI_PRODUCT_NAME, "Venue 11 Pro 7130"),
++ },
++ },
++ {
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "HP Stream x360 Convertible PC 11"),
++ },
++ },
++ {} /* Array terminator */
++};
++
+ static bool intel_vbtn_has_switches(acpi_handle handle)
+ {
+- const char *chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);
+ unsigned long long vgbs;
+ acpi_status status;
+
+- /*
+- * Some normal laptops have a VGBS method despite being non-convertible
+- * and their VGBS method always returns 0, causing detect_tablet_mode()
+- * to report SW_TABLET_MODE=1 to userspace, which causes issues.
+- * These laptops have a DMI chassis_type of 9 ("Laptop"), do not report
+- * switches on any devices with a DMI chassis_type of 9.
+- */
+- if (chassis_type && strcmp(chassis_type, "9") == 0)
++ if (!dmi_check_system(dmi_switches_allow_list))
+ return false;
+
+ status = acpi_evaluate_integer(handle, "VGBS", NULL, &vgbs);
+diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
+index 0f6fceda5fc0b..fe8386ab363c9 100644
+--- a/drivers/platform/x86/thinkpad_acpi.c
++++ b/drivers/platform/x86/thinkpad_acpi.c
+@@ -2569,7 +2569,7 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn,
+ */
+ static int hotkey_kthread(void *data)
+ {
+- struct tp_nvram_state s[2];
++ struct tp_nvram_state s[2] = { 0 };
+ u32 poll_mask, event_mask;
+ unsigned int si, so;
+ unsigned long t;
+@@ -6829,8 +6829,10 @@ static int __init tpacpi_query_bcl_levels(acpi_handle handle)
+ list_for_each_entry(child, &device->children, node) {
+ acpi_status status = acpi_evaluate_object(child->handle, "_BCL",
+ NULL, &buffer);
+- if (ACPI_FAILURE(status))
++ if (ACPI_FAILURE(status)) {
++ buffer.length = ACPI_ALLOCATE_BUFFER;
+ continue;
++ }
+
+ obj = (union acpi_object *)buffer.pointer;
+ if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
+diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
+index 31bb3647a99c3..8e74654c1b271 100644
+--- a/drivers/tty/vt/selection.c
++++ b/drivers/tty/vt/selection.c
+@@ -193,7 +193,7 @@ static int vc_selection_store_chars(struct vc_data *vc, bool unicode)
+ /* Allocate a new buffer before freeing the old one ... */
+ /* chars can take up to 4 bytes with unicode */
+ bp = kmalloc_array((vc_sel.end - vc_sel.start) / 2 + 1, unicode ? 4 : 1,
+- GFP_KERNEL);
++ GFP_KERNEL | __GFP_NOWARN);
+ if (!bp) {
+ printk(KERN_WARNING "selection: kmalloc() failed\n");
+ clear_selection();
+diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
+index a54b60d6623f0..e172c2efc663c 100644
+--- a/drivers/vhost/vdpa.c
++++ b/drivers/vhost/vdpa.c
+@@ -527,6 +527,9 @@ static int vhost_vdpa_map(struct vhost_vdpa *v,
+ r = iommu_map(v->domain, iova, pa, size,
+ perm_to_iommu_flags(perm));
+
++ if (r)
++ vhost_iotlb_del_range(dev->iotlb, iova, iova + size - 1);
++
+ return r;
+ }
+
+@@ -552,21 +555,19 @@ static int vhost_vdpa_process_iotlb_update(struct vhost_vdpa *v,
+ struct vhost_dev *dev = &v->vdev;
+ struct vhost_iotlb *iotlb = dev->iotlb;
+ struct page **page_list;
+- unsigned long list_size = PAGE_SIZE / sizeof(struct page *);
++ struct vm_area_struct **vmas;
+ unsigned int gup_flags = FOLL_LONGTERM;
+- unsigned long npages, cur_base, map_pfn, last_pfn = 0;
+- unsigned long locked, lock_limit, pinned, i;
++ unsigned long map_pfn, last_pfn = 0;
++ unsigned long npages, lock_limit;
++ unsigned long i, nmap = 0;
+ u64 iova = msg->iova;
++ long pinned;
+ int ret = 0;
+
+ if (vhost_iotlb_itree_first(iotlb, msg->iova,
+ msg->iova + msg->size - 1))
+ return -EEXIST;
+
+- page_list = (struct page **) __get_free_page(GFP_KERNEL);
+- if (!page_list)
+- return -ENOMEM;
+-
+ if (msg->perm & VHOST_ACCESS_WO)
+ gup_flags |= FOLL_WRITE;
+
+@@ -574,61 +575,86 @@ static int vhost_vdpa_process_iotlb_update(struct vhost_vdpa *v,
+ if (!npages)
+ return -EINVAL;
+
++ page_list = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
++ vmas = kvmalloc_array(npages, sizeof(struct vm_area_struct *),
++ GFP_KERNEL);
++ if (!page_list || !vmas) {
++ ret = -ENOMEM;
++ goto free;
++ }
++
+ mmap_read_lock(dev->mm);
+
+- locked = atomic64_add_return(npages, &dev->mm->pinned_vm);
+ lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+-
+- if (locked > lock_limit) {
++ if (npages + atomic64_read(&dev->mm->pinned_vm) > lock_limit) {
+ ret = -ENOMEM;
+- goto out;
++ goto unlock;
+ }
+
+- cur_base = msg->uaddr & PAGE_MASK;
+- iova &= PAGE_MASK;
++ pinned = pin_user_pages(msg->uaddr & PAGE_MASK, npages, gup_flags,
++ page_list, vmas);
++ if (npages != pinned) {
++ if (pinned < 0) {
++ ret = pinned;
++ } else {
++ unpin_user_pages(page_list, pinned);
++ ret = -ENOMEM;
++ }
++ goto unlock;
++ }
+
+- while (npages) {
+- pinned = min_t(unsigned long, npages, list_size);
+- ret = pin_user_pages(cur_base, pinned,
+- gup_flags, page_list, NULL);
+- if (ret != pinned)
+- goto out;
+-
+- if (!last_pfn)
+- map_pfn = page_to_pfn(page_list[0]);
+-
+- for (i = 0; i < ret; i++) {
+- unsigned long this_pfn = page_to_pfn(page_list[i]);
+- u64 csize;
+-
+- if (last_pfn && (this_pfn != last_pfn + 1)) {
+- /* Pin a contiguous chunk of memory */
+- csize = (last_pfn - map_pfn + 1) << PAGE_SHIFT;
+- if (vhost_vdpa_map(v, iova, csize,
+- map_pfn << PAGE_SHIFT,
+- msg->perm))
+- goto out;
+- map_pfn = this_pfn;
+- iova += csize;
++ iova &= PAGE_MASK;
++ map_pfn = page_to_pfn(page_list[0]);
++
++ /* One more iteration to avoid extra vdpa_map() call out of loop. */
++ for (i = 0; i <= npages; i++) {
++ unsigned long this_pfn;
++ u64 csize;
++
++ /* The last chunk may have no valid PFN next to it */
++ this_pfn = i < npages ? page_to_pfn(page_list[i]) : -1UL;
++
++ if (last_pfn && (this_pfn == -1UL ||
++ this_pfn != last_pfn + 1)) {
++ /* Pin a contiguous chunk of memory */
++ csize = last_pfn - map_pfn + 1;
++ ret = vhost_vdpa_map(v, iova, csize << PAGE_SHIFT,
++ map_pfn << PAGE_SHIFT,
++ msg->perm);
++ if (ret) {
++ /*
++ * Unpin the rest chunks of memory on the
++ * flight with no corresponding vdpa_map()
++ * calls having been made yet. On the other
++ * hand, vdpa_unmap() in the failure path
++ * is in charge of accounting the number of
++ * pinned pages for its own.
++ * This asymmetrical pattern of accounting
++ * is for efficiency to pin all pages at
++ * once, while there is no other callsite
++ * of vdpa_map() than here above.
++ */
++ unpin_user_pages(&page_list[nmap],
++ npages - nmap);
++ goto out;
+ }
+-
+- last_pfn = this_pfn;
++ atomic64_add(csize, &dev->mm->pinned_vm);
++ nmap += csize;
++ iova += csize << PAGE_SHIFT;
++ map_pfn = this_pfn;
+ }
+-
+- cur_base += ret << PAGE_SHIFT;
+- npages -= ret;
++ last_pfn = this_pfn;
+ }
+
+- /* Pin the rest chunk */
+- ret = vhost_vdpa_map(v, iova, (last_pfn - map_pfn + 1) << PAGE_SHIFT,
+- map_pfn << PAGE_SHIFT, msg->perm);
++ WARN_ON(nmap != npages);
+ out:
+- if (ret) {
++ if (ret)
+ vhost_vdpa_unmap(v, msg->iova, msg->size);
+- atomic64_sub(npages, &dev->mm->pinned_vm);
+- }
++unlock:
+ mmap_read_unlock(dev->mm);
+- free_page((unsigned long)page_list);
++free:
++ kvfree(vmas);
++ kvfree(page_list);
+ return ret;
+ }
+
+diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
+index d7b8df3edffcf..5f0030e086888 100644
+--- a/drivers/vhost/vhost.c
++++ b/drivers/vhost/vhost.c
+@@ -1283,6 +1283,11 @@ static bool vq_access_ok(struct vhost_virtqueue *vq, unsigned int num,
+ vring_used_t __user *used)
+
+ {
++ /* If an IOTLB device is present, the vring addresses are
++ * GIOVAs. Access validation occurs at prefetch time. */
++ if (vq->iotlb)
++ return true;
++
+ return access_ok(desc, vhost_get_desc_size(vq, num)) &&
+ access_ok(avail, vhost_get_avail_size(vq, num)) &&
+ access_ok(used, vhost_get_used_size(vq, num));
+@@ -1376,10 +1381,6 @@ bool vhost_vq_access_ok(struct vhost_virtqueue *vq)
+ if (!vq_log_access_ok(vq, vq->log_base))
+ return false;
+
+- /* Access validation occurs at prefetch time with IOTLB */
+- if (vq->iotlb)
+- return true;
+-
+ return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used);
+ }
+ EXPORT_SYMBOL_GPL(vhost_vq_access_ok);
+@@ -1511,8 +1512,7 @@ static long vhost_vring_set_addr(struct vhost_dev *d,
+ /* Also validate log access for used ring if enabled. */
+ if ((a.flags & (0x1 << VHOST_VRING_F_LOG)) &&
+ !log_access_ok(vq->log_base, a.log_guest_addr,
+- sizeof *vq->used +
+- vq->num * sizeof *vq->used->ring))
++ vhost_get_used_size(vq, vq->num)))
+ return -EINVAL;
+ }
+
+diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
+index df3c52d721597..8653950c56d45 100644
+--- a/drivers/video/console/newport_con.c
++++ b/drivers/video/console/newport_con.c
+@@ -35,12 +35,6 @@
+
+ #define FONT_DATA ((unsigned char *)font_vga_8x16.data)
+
+-/* borrowed from fbcon.c */
+-#define REFCOUNT(fd) (((int *)(fd))[-1])
+-#define FNTSIZE(fd) (((int *)(fd))[-2])
+-#define FNTCHARCNT(fd) (((int *)(fd))[-3])
+-#define FONT_EXTRA_WORDS 3
+-
+ static unsigned char *font_data[MAX_NR_CONSOLES];
+
+ static struct newport_regs *npregs;
+@@ -522,6 +516,7 @@ static int newport_set_font(int unit, struct console_font *op)
+ FNTSIZE(new_data) = size;
+ FNTCHARCNT(new_data) = op->charcount;
+ REFCOUNT(new_data) = 0; /* usage counter */
++ FNTSUM(new_data) = 0;
+
+ p = new_data;
+ for (i = 0; i < op->charcount; i++) {
+diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
+index 09cb46e94f405..3e82f632841d9 100644
+--- a/drivers/video/fbdev/core/fbcon.c
++++ b/drivers/video/fbdev/core/fbcon.c
+@@ -2299,6 +2299,9 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
+
+ if (font->width <= 8) {
+ j = vc->vc_font.height;
++ if (font->charcount * j > FNTSIZE(fontdata))
++ return -EINVAL;
++
+ for (i = 0; i < font->charcount; i++) {
+ memcpy(data, fontdata, j);
+ memset(data + j, 0, 32 - j);
+@@ -2307,6 +2310,9 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
+ }
+ } else if (font->width <= 16) {
+ j = vc->vc_font.height * 2;
++ if (font->charcount * j > FNTSIZE(fontdata))
++ return -EINVAL;
++
+ for (i = 0; i < font->charcount; i++) {
+ memcpy(data, fontdata, j);
+ memset(data + j, 0, 64 - j);
+@@ -2314,6 +2320,9 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
+ fontdata += j;
+ }
+ } else if (font->width <= 24) {
++ if (font->charcount * (vc->vc_font.height * sizeof(u32)) > FNTSIZE(fontdata))
++ return -EINVAL;
++
+ for (i = 0; i < font->charcount; i++) {
+ for (j = 0; j < vc->vc_font.height; j++) {
+ *data++ = fontdata[0];
+@@ -2326,6 +2335,9 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
+ }
+ } else {
+ j = vc->vc_font.height * 4;
++ if (font->charcount * j > FNTSIZE(fontdata))
++ return -EINVAL;
++
+ for (i = 0; i < font->charcount; i++) {
+ memcpy(data, fontdata, j);
+ memset(data + j, 0, 128 - j);
+diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
+index 78bb14c03643e..9315b360c8981 100644
+--- a/drivers/video/fbdev/core/fbcon.h
++++ b/drivers/video/fbdev/core/fbcon.h
+@@ -152,13 +152,6 @@ static inline int attr_col_ec(int shift, struct vc_data *vc,
+ #define attr_bgcol_ec(bgshift, vc, info) attr_col_ec(bgshift, vc, info, 0)
+ #define attr_fgcol_ec(fgshift, vc, info) attr_col_ec(fgshift, vc, info, 1)
+
+-/* Font */
+-#define REFCOUNT(fd) (((int *)(fd))[-1])
+-#define FNTSIZE(fd) (((int *)(fd))[-2])
+-#define FNTCHARCNT(fd) (((int *)(fd))[-3])
+-#define FNTSUM(fd) (((int *)(fd))[-4])
+-#define FONT_EXTRA_WORDS 4
+-
+ /*
+ * Scroll Method
+ */
+diff --git a/drivers/video/fbdev/core/fbcon_rotate.c b/drivers/video/fbdev/core/fbcon_rotate.c
+index c0d445294aa7c..ac72d4f85f7d0 100644
+--- a/drivers/video/fbdev/core/fbcon_rotate.c
++++ b/drivers/video/fbdev/core/fbcon_rotate.c
+@@ -14,6 +14,7 @@
+ #include <linux/fb.h>
+ #include <linux/vt_kern.h>
+ #include <linux/console.h>
++#include <linux/font.h>
+ #include <asm/types.h>
+ #include "fbcon.h"
+ #include "fbcon_rotate.h"
+diff --git a/drivers/video/fbdev/core/tileblit.c b/drivers/video/fbdev/core/tileblit.c
+index eb664dbf96f66..adff8d6ffe6f9 100644
+--- a/drivers/video/fbdev/core/tileblit.c
++++ b/drivers/video/fbdev/core/tileblit.c
+@@ -13,6 +13,7 @@
+ #include <linux/fb.h>
+ #include <linux/vt_kern.h>
+ #include <linux/console.h>
++#include <linux/font.h>
+ #include <asm/types.h>
+ #include "fbcon.h"
+
+diff --git a/fs/afs/inode.c b/fs/afs/inode.c
+index 1d13d2e882ada..0fe8844b4bee2 100644
+--- a/fs/afs/inode.c
++++ b/fs/afs/inode.c
+@@ -810,14 +810,32 @@ void afs_evict_inode(struct inode *inode)
+
+ static void afs_setattr_success(struct afs_operation *op)
+ {
+- struct inode *inode = &op->file[0].vnode->vfs_inode;
++ struct afs_vnode_param *vp = &op->file[0];
++ struct inode *inode = &vp->vnode->vfs_inode;
++ loff_t old_i_size = i_size_read(inode);
++
++ op->setattr.old_i_size = old_i_size;
++ afs_vnode_commit_status(op, vp);
++ /* inode->i_size has now been changed. */
++
++ if (op->setattr.attr->ia_valid & ATTR_SIZE) {
++ loff_t size = op->setattr.attr->ia_size;
++ if (size > old_i_size)
++ pagecache_isize_extended(inode, old_i_size, size);
++ }
++}
++
++static void afs_setattr_edit_file(struct afs_operation *op)
++{
++ struct afs_vnode_param *vp = &op->file[0];
++ struct inode *inode = &vp->vnode->vfs_inode;
+
+- afs_vnode_commit_status(op, &op->file[0]);
+ if (op->setattr.attr->ia_valid & ATTR_SIZE) {
+- loff_t i_size = inode->i_size, size = op->setattr.attr->ia_size;
+- if (size > i_size)
+- pagecache_isize_extended(inode, i_size, size);
+- truncate_pagecache(inode, size);
++ loff_t size = op->setattr.attr->ia_size;
++ loff_t i_size = op->setattr.old_i_size;
++
++ if (size < i_size)
++ truncate_pagecache(inode, size);
+ }
+ }
+
+@@ -825,6 +843,7 @@ static const struct afs_operation_ops afs_setattr_operation = {
+ .issue_afs_rpc = afs_fs_setattr,
+ .issue_yfs_rpc = yfs_fs_setattr,
+ .success = afs_setattr_success,
++ .edit_dir = afs_setattr_edit_file,
+ };
+
+ /*
+@@ -863,11 +882,16 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
+ if (S_ISREG(vnode->vfs_inode.i_mode))
+ filemap_write_and_wait(vnode->vfs_inode.i_mapping);
+
++ /* Prevent any new writebacks from starting whilst we do this. */
++ down_write(&vnode->validate_lock);
++
+ op = afs_alloc_operation(((attr->ia_valid & ATTR_FILE) ?
+ afs_file_key(attr->ia_file) : NULL),
+ vnode->volume);
+- if (IS_ERR(op))
+- return PTR_ERR(op);
++ if (IS_ERR(op)) {
++ ret = PTR_ERR(op);
++ goto out_unlock;
++ }
+
+ afs_op_set_vnode(op, 0, vnode);
+ op->setattr.attr = attr;
+@@ -880,5 +904,10 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
+ op->file[0].update_ctime = 1;
+
+ op->ops = &afs_setattr_operation;
+- return afs_do_sync_operation(op);
++ ret = afs_do_sync_operation(op);
++
++out_unlock:
++ up_write(&vnode->validate_lock);
++ _leave(" = %d", ret);
++ return ret;
+ }
+diff --git a/fs/afs/internal.h b/fs/afs/internal.h
+index 792ac711985eb..e1ebead2e505a 100644
+--- a/fs/afs/internal.h
++++ b/fs/afs/internal.h
+@@ -810,6 +810,7 @@ struct afs_operation {
+ } store;
+ struct {
+ struct iattr *attr;
++ loff_t old_i_size;
+ } setattr;
+ struct afs_acl *acl;
+ struct yfs_acl *yacl;
+diff --git a/fs/afs/write.c b/fs/afs/write.c
+index a121c247d95a3..0a98cf36e78a3 100644
+--- a/fs/afs/write.c
++++ b/fs/afs/write.c
+@@ -738,11 +738,21 @@ static int afs_writepages_region(struct address_space *mapping,
+ int afs_writepages(struct address_space *mapping,
+ struct writeback_control *wbc)
+ {
++ struct afs_vnode *vnode = AFS_FS_I(mapping->host);
+ pgoff_t start, end, next;
+ int ret;
+
+ _enter("");
+
++ /* We have to be careful as we can end up racing with setattr()
++ * truncating the pagecache since the caller doesn't take a lock here
++ * to prevent it.
++ */
++ if (wbc->sync_mode == WB_SYNC_ALL)
++ down_read(&vnode->validate_lock);
++ else if (!down_read_trylock(&vnode->validate_lock))
++ return 0;
++
+ if (wbc->range_cyclic) {
+ start = mapping->writeback_index;
+ end = -1;
+@@ -762,6 +772,7 @@ int afs_writepages(struct address_space *mapping,
+ ret = afs_writepages_region(mapping, wbc, start, end, &next);
+ }
+
++ up_read(&vnode->validate_lock);
+ _leave(" = %d", ret);
+ return ret;
+ }
+diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
+index eb86e4b88c73a..e4a1c6afe35dc 100644
+--- a/fs/btrfs/dev-replace.c
++++ b/fs/btrfs/dev-replace.c
+@@ -783,7 +783,9 @@ error:
+ /* replace the sysfs entry */
+ btrfs_sysfs_remove_devices_dir(fs_info->fs_devices, src_device);
+ btrfs_sysfs_update_devid(tgt_device);
+- btrfs_rm_dev_replace_free_srcdev(src_device);
++ if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &src_device->dev_state))
++ btrfs_scratch_superblocks(fs_info, src_device->bdev,
++ src_device->name->str);
+
+ /* write back the superblocks */
+ trans = btrfs_start_transaction(root, 0);
+@@ -792,6 +794,8 @@ error:
+
+ mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
+
++ btrfs_rm_dev_replace_free_srcdev(src_device);
++
+ return 0;
+ }
+
+diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
+index 956eb0d6bc584..79e9a80bd37a0 100644
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -1999,9 +1999,9 @@ static u64 btrfs_num_devices(struct btrfs_fs_info *fs_info)
+ return num_devices;
+ }
+
+-static void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
+- struct block_device *bdev,
+- const char *device_path)
++void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
++ struct block_device *bdev,
++ const char *device_path)
+ {
+ struct btrfs_super_block *disk_super;
+ int copy_num;
+@@ -2224,11 +2224,7 @@ void btrfs_rm_dev_replace_free_srcdev(struct btrfs_device *srcdev)
+ struct btrfs_fs_info *fs_info = srcdev->fs_info;
+ struct btrfs_fs_devices *fs_devices = srcdev->fs_devices;
+
+- if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &srcdev->dev_state)) {
+- /* zero out the old super if it is writable */
+- btrfs_scratch_superblocks(fs_info, srcdev->bdev,
+- srcdev->name->str);
+- }
++ mutex_lock(&uuid_mutex);
+
+ btrfs_close_bdev(srcdev);
+ synchronize_rcu();
+@@ -2258,6 +2254,7 @@ void btrfs_rm_dev_replace_free_srcdev(struct btrfs_device *srcdev)
+ close_fs_devices(fs_devices);
+ free_fs_devices(fs_devices);
+ }
++ mutex_unlock(&uuid_mutex);
+ }
+
+ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev)
+diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
+index 75af2334b2e37..83862e27f5663 100644
+--- a/fs/btrfs/volumes.h
++++ b/fs/btrfs/volumes.h
+@@ -573,6 +573,9 @@ void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info);
+ void btrfs_reset_fs_info_ptr(struct btrfs_fs_info *fs_info);
+ bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info,
+ struct btrfs_device *failing_dev);
++void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
++ struct block_device *bdev,
++ const char *device_path);
+
+ int btrfs_bg_type_to_factor(u64 flags);
+ const char *btrfs_bg_type_to_raid_name(u64 flags);
+diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
+index 32f90dc82c840..d44df8f95bcd4 100644
+--- a/fs/cifs/smb2ops.c
++++ b/fs/cifs/smb2ops.c
+@@ -1208,7 +1208,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
+ rqst[1].rq_iov = si_iov;
+ rqst[1].rq_nvec = 1;
+
+- len = sizeof(ea) + ea_name_len + ea_value_len + 1;
++ len = sizeof(*ea) + ea_name_len + ea_value_len + 1;
+ ea = kzalloc(len, GFP_KERNEL);
+ if (ea == NULL) {
+ rc = -ENOMEM;
+diff --git a/fs/exfat/cache.c b/fs/exfat/cache.c
+index 03d0824fc368a..5a2f119b7e8c7 100644
+--- a/fs/exfat/cache.c
++++ b/fs/exfat/cache.c
+@@ -17,7 +17,6 @@
+ #include "exfat_raw.h"
+ #include "exfat_fs.h"
+
+-#define EXFAT_CACHE_VALID 0
+ #define EXFAT_MAX_CACHE 16
+
+ struct exfat_cache {
+@@ -61,16 +60,6 @@ void exfat_cache_shutdown(void)
+ kmem_cache_destroy(exfat_cachep);
+ }
+
+-void exfat_cache_init_inode(struct inode *inode)
+-{
+- struct exfat_inode_info *ei = EXFAT_I(inode);
+-
+- spin_lock_init(&ei->cache_lru_lock);
+- ei->nr_caches = 0;
+- ei->cache_valid_id = EXFAT_CACHE_VALID + 1;
+- INIT_LIST_HEAD(&ei->cache_lru);
+-}
+-
+ static inline struct exfat_cache *exfat_cache_alloc(void)
+ {
+ return kmem_cache_alloc(exfat_cachep, GFP_NOFS);
+diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
+index 75c7bdbeba6d3..fb49928687bb5 100644
+--- a/fs/exfat/exfat_fs.h
++++ b/fs/exfat/exfat_fs.h
+@@ -250,6 +250,8 @@ struct exfat_sb_info {
+ struct rcu_head rcu;
+ };
+
++#define EXFAT_CACHE_VALID 0
++
+ /*
+ * EXFAT file system inode in-memory data
+ */
+@@ -429,7 +431,6 @@ extern const struct dentry_operations exfat_utf8_dentry_ops;
+ /* cache.c */
+ int exfat_cache_init(void);
+ void exfat_cache_shutdown(void);
+-void exfat_cache_init_inode(struct inode *inode);
+ void exfat_cache_inval_inode(struct inode *inode);
+ int exfat_get_cluster(struct inode *inode, unsigned int cluster,
+ unsigned int *fclus, unsigned int *dclus,
+diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
+index cf9ca6c4d046e..1952b88e14dbd 100644
+--- a/fs/exfat/inode.c
++++ b/fs/exfat/inode.c
+@@ -610,8 +610,6 @@ static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info)
+ ei->i_crtime = info->crtime;
+ inode->i_atime = info->atime;
+
+- exfat_cache_init_inode(inode);
+-
+ return 0;
+ }
+
+diff --git a/fs/exfat/super.c b/fs/exfat/super.c
+index 253a92460d522..142f3459c7ca7 100644
+--- a/fs/exfat/super.c
++++ b/fs/exfat/super.c
+@@ -361,7 +361,6 @@ static int exfat_read_root(struct inode *inode)
+ inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
+ current_time(inode);
+ exfat_truncate_atime(&inode->i_atime);
+- exfat_cache_init_inode(inode);
+ return 0;
+ }
+
+@@ -747,6 +746,10 @@ static void exfat_inode_init_once(void *foo)
+ {
+ struct exfat_inode_info *ei = (struct exfat_inode_info *)foo;
+
++ spin_lock_init(&ei->cache_lru_lock);
++ ei->nr_caches = 0;
++ ei->cache_valid_id = EXFAT_CACHE_VALID + 1;
++ INIT_LIST_HEAD(&ei->cache_lru);
+ INIT_HLIST_NODE(&ei->i_hash_fat);
+ inode_init_once(&ei->vfs_inode);
+ }
+diff --git a/fs/io_uring.c b/fs/io_uring.c
+index ebc3586b18795..d2bb2ae9551f0 100644
+--- a/fs/io_uring.c
++++ b/fs/io_uring.c
+@@ -7998,11 +7998,19 @@ static int io_uring_show_cred(int id, void *p, void *data)
+
+ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m)
+ {
++ bool has_lock;
+ int i;
+
+- mutex_lock(&ctx->uring_lock);
++ /*
++ * Avoid ABBA deadlock between the seq lock and the io_uring mutex,
++ * since fdinfo case grabs it in the opposite direction of normal use
++ * cases. If we fail to get the lock, we just don't iterate any
++ * structures that could be going away outside the io_uring mutex.
++ */
++ has_lock = mutex_trylock(&ctx->uring_lock);
++
+ seq_printf(m, "UserFiles:\t%u\n", ctx->nr_user_files);
+- for (i = 0; i < ctx->nr_user_files; i++) {
++ for (i = 0; has_lock && i < ctx->nr_user_files; i++) {
+ struct fixed_file_table *table;
+ struct file *f;
+
+@@ -8014,13 +8022,13 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m)
+ seq_printf(m, "%5u: <none>\n", i);
+ }
+ seq_printf(m, "UserBufs:\t%u\n", ctx->nr_user_bufs);
+- for (i = 0; i < ctx->nr_user_bufs; i++) {
++ for (i = 0; has_lock && i < ctx->nr_user_bufs; i++) {
+ struct io_mapped_ubuf *buf = &ctx->user_bufs[i];
+
+ seq_printf(m, "%5u: 0x%llx/%u\n", i, buf->ubuf,
+ (unsigned int) buf->len);
+ }
+- if (!idr_is_empty(&ctx->personality_idr)) {
++ if (has_lock && !idr_is_empty(&ctx->personality_idr)) {
+ seq_printf(m, "Personalities:\n");
+ idr_for_each(&ctx->personality_idr, io_uring_show_cred, m);
+ }
+@@ -8035,7 +8043,8 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m)
+ req->task->task_works != NULL);
+ }
+ spin_unlock_irq(&ctx->completion_lock);
+- mutex_unlock(&ctx->uring_lock);
++ if (has_lock)
++ mutex_unlock(&ctx->uring_lock);
+ }
+
+ static void io_uring_show_fdinfo(struct seq_file *m, struct file *f)
+diff --git a/fs/pipe.c b/fs/pipe.c
+index 117db82b10af5..0ac197658a2d6 100644
+--- a/fs/pipe.c
++++ b/fs/pipe.c
+@@ -894,19 +894,18 @@ int create_pipe_files(struct file **res, int flags)
+ {
+ struct inode *inode = get_pipe_inode();
+ struct file *f;
++ int error;
+
+ if (!inode)
+ return -ENFILE;
+
+ if (flags & O_NOTIFICATION_PIPE) {
+-#ifdef CONFIG_WATCH_QUEUE
+- if (watch_queue_init(inode->i_pipe) < 0) {
++ error = watch_queue_init(inode->i_pipe);
++ if (error) {
++ free_pipe_info(inode->i_pipe);
+ iput(inode);
+- return -ENOMEM;
++ return error;
+ }
+-#else
+- return -ENOPKG;
+-#endif
+ }
+
+ f = alloc_file_pseudo(inode, pipe_mnt, "",
+diff --git a/fs/splice.c b/fs/splice.c
+index c3d00dfc73446..ce75aec522744 100644
+--- a/fs/splice.c
++++ b/fs/splice.c
+@@ -526,6 +526,22 @@ static int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_des
+ return 1;
+ }
+
++/* We know we have a pipe buffer, but maybe it's empty? */
++static inline bool eat_empty_buffer(struct pipe_inode_info *pipe)
++{
++ unsigned int tail = pipe->tail;
++ unsigned int mask = pipe->ring_size - 1;
++ struct pipe_buffer *buf = &pipe->bufs[tail & mask];
++
++ if (unlikely(!buf->len)) {
++ pipe_buf_release(pipe, buf);
++ pipe->tail = tail+1;
++ return true;
++ }
++
++ return false;
++}
++
+ /**
+ * splice_from_pipe_next - wait for some data to splice from
+ * @pipe: pipe to splice from
+@@ -545,6 +561,7 @@ static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_des
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
++repeat:
+ while (pipe_empty(pipe->head, pipe->tail)) {
+ if (!pipe->writers)
+ return 0;
+@@ -566,6 +583,9 @@ static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_des
+ pipe_wait_readable(pipe);
+ }
+
++ if (eat_empty_buffer(pipe))
++ goto repeat;
++
+ return 1;
+ }
+
+diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
+index 9e9b1ec30b902..d7eb9e7689b45 100644
+--- a/include/asm-generic/vmlinux.lds.h
++++ b/include/asm-generic/vmlinux.lds.h
+@@ -641,7 +641,7 @@
+ #define BTF \
+ .BTF : AT(ADDR(.BTF) - LOAD_OFFSET) { \
+ __start_BTF = .; \
+- *(.BTF) \
++ KEEP(*(.BTF)) \
+ __stop_BTF = .; \
+ }
+ #else
+diff --git a/include/linux/font.h b/include/linux/font.h
+index 51b91c8b69d58..59faa80f586df 100644
+--- a/include/linux/font.h
++++ b/include/linux/font.h
+@@ -59,4 +59,17 @@ extern const struct font_desc *get_default_font(int xres, int yres,
+ /* Max. length for the name of a predefined font */
+ #define MAX_FONT_NAME 32
+
++/* Extra word getters */
++#define REFCOUNT(fd) (((int *)(fd))[-1])
++#define FNTSIZE(fd) (((int *)(fd))[-2])
++#define FNTCHARCNT(fd) (((int *)(fd))[-3])
++#define FNTSUM(fd) (((int *)(fd))[-4])
++
++#define FONT_EXTRA_WORDS 4
++
++struct font_data {
++ unsigned int extra[FONT_EXTRA_WORDS];
++ const unsigned char data[];
++} __packed;
++
+ #endif /* _VIDEO_FONT_H */
+diff --git a/include/linux/khugepaged.h b/include/linux/khugepaged.h
+index bc45ea1efbf79..c941b73773216 100644
+--- a/include/linux/khugepaged.h
++++ b/include/linux/khugepaged.h
+@@ -15,6 +15,7 @@ extern int __khugepaged_enter(struct mm_struct *mm);
+ extern void __khugepaged_exit(struct mm_struct *mm);
+ extern int khugepaged_enter_vma_merge(struct vm_area_struct *vma,
+ unsigned long vm_flags);
++extern void khugepaged_min_free_kbytes_update(void);
+ #ifdef CONFIG_SHMEM
+ extern void collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr);
+ #else
+@@ -85,6 +86,10 @@ static inline void collapse_pte_mapped_thp(struct mm_struct *mm,
+ unsigned long addr)
+ {
+ }
++
++static inline void khugepaged_min_free_kbytes_update(void)
++{
++}
+ #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+
+ #endif /* _LINUX_KHUGEPAGED_H */
+diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
+index 1e6ca716635a9..484cd8ba869c5 100644
+--- a/include/linux/mlx5/driver.h
++++ b/include/linux/mlx5/driver.h
+@@ -764,6 +764,8 @@ struct mlx5_cmd_work_ent {
+ u64 ts2;
+ u16 op;
+ bool polling;
++ /* Track the max comp handlers */
++ refcount_t refcnt;
+ };
+
+ struct mlx5_pas {
+diff --git a/include/linux/net.h b/include/linux/net.h
+index 016a9c5faa347..5fab2dcd3364c 100644
+--- a/include/linux/net.h
++++ b/include/linux/net.h
+@@ -21,6 +21,7 @@
+ #include <linux/rcupdate.h>
+ #include <linux/once.h>
+ #include <linux/fs.h>
++#include <linux/mm.h>
+
+ #include <uapi/linux/net.h>
+
+@@ -290,6 +291,21 @@ do { \
+ #define net_get_random_once_wait(buf, nbytes) \
+ get_random_once_wait((buf), (nbytes))
+
++/*
++ * E.g. XFS meta- & log-data is in slab pages, or bcache meta
++ * data pages, or other high order pages allocated by
++ * __get_free_pages() without __GFP_COMP, which have a page_count
++ * of 0 and/or have PageSlab() set. We cannot use send_page for
++ * those, as that does get_page(); put_page(); and would cause
++ * either a VM_BUG directly, or __page_cache_release a page that
++ * would actually still be referenced by someone, leading to some
++ * obscure delayed Oops somewhere else.
++ */
++static inline bool sendpage_ok(struct page *page)
++{
++ return !PageSlab(page) && page_count(page) >= 1;
++}
++
+ int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec,
+ size_t num, size_t len);
+ int kernel_sendmsg_locked(struct sock *sk, struct msghdr *msg,
+diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
+index cf2468da68e91..601ad6957bb9d 100644
+--- a/include/linux/pagemap.h
++++ b/include/linux/pagemap.h
+@@ -54,7 +54,8 @@ static inline void mapping_set_error(struct address_space *mapping, int error)
+ __filemap_set_wb_err(mapping, error);
+
+ /* Record it in superblock */
+- errseq_set(&mapping->host->i_sb->s_wb_err, error);
++ if (mapping->host)
++ errseq_set(&mapping->host->i_sb->s_wb_err, error);
+
+ /* Record it in flags for now, for legacy callers */
+ if (error == -ENOSPC)
+diff --git a/include/linux/watch_queue.h b/include/linux/watch_queue.h
+index 5e08db2adc319..c994d1b2cdbaa 100644
+--- a/include/linux/watch_queue.h
++++ b/include/linux/watch_queue.h
+@@ -122,6 +122,12 @@ static inline void remove_watch_list(struct watch_list *wlist, u64 id)
+ */
+ #define watch_sizeof(STRUCT) (sizeof(STRUCT) << WATCH_INFO_LENGTH__SHIFT)
+
++#else
++static inline int watch_queue_init(struct pipe_inode_info *pipe)
++{
++ return -ENOPKG;
++}
++
+ #endif
+
+ #endif /* _LINUX_WATCH_QUEUE_H */
+diff --git a/include/net/act_api.h b/include/net/act_api.h
+index 8c39348806705..7dc88ebb6e3e7 100644
+--- a/include/net/act_api.h
++++ b/include/net/act_api.h
+@@ -166,8 +166,6 @@ int tcf_idr_create_from_flags(struct tc_action_net *tn, u32 index,
+ struct nlattr *est, struct tc_action **a,
+ const struct tc_action_ops *ops, int bind,
+ u32 flags);
+-void tcf_idr_insert(struct tc_action_net *tn, struct tc_action *a);
+-
+ void tcf_idr_cleanup(struct tc_action_net *tn, u32 index);
+ int tcf_idr_check_alloc(struct tc_action_net *tn, u32 *index,
+ struct tc_action **a, int bind);
+diff --git a/include/net/netlink.h b/include/net/netlink.h
+index c0411f14fb53b..6df0c91870a3e 100644
+--- a/include/net/netlink.h
++++ b/include/net/netlink.h
+@@ -1936,7 +1936,8 @@ void nla_get_range_signed(const struct nla_policy *pt,
+ int netlink_policy_dump_start(const struct nla_policy *policy,
+ unsigned int maxtype,
+ unsigned long *state);
+-bool netlink_policy_dump_loop(unsigned long *state);
++bool netlink_policy_dump_loop(unsigned long state);
+ int netlink_policy_dump_write(struct sk_buff *skb, unsigned long state);
++void netlink_policy_dump_free(unsigned long state);
+
+ #endif
+diff --git a/include/net/xfrm.h b/include/net/xfrm.h
+index 51f65d23ebafa..2e32cb10ac16b 100644
+--- a/include/net/xfrm.h
++++ b/include/net/xfrm.h
+@@ -1767,21 +1767,17 @@ static inline unsigned int xfrm_replay_state_esn_len(struct xfrm_replay_state_es
+ static inline int xfrm_replay_clone(struct xfrm_state *x,
+ struct xfrm_state *orig)
+ {
+- x->replay_esn = kzalloc(xfrm_replay_state_esn_len(orig->replay_esn),
++
++ x->replay_esn = kmemdup(orig->replay_esn,
++ xfrm_replay_state_esn_len(orig->replay_esn),
+ GFP_KERNEL);
+ if (!x->replay_esn)
+ return -ENOMEM;
+-
+- x->replay_esn->bmp_len = orig->replay_esn->bmp_len;
+- x->replay_esn->replay_window = orig->replay_esn->replay_window;
+-
+- x->preplay_esn = kmemdup(x->replay_esn,
+- xfrm_replay_state_esn_len(x->replay_esn),
++ x->preplay_esn = kmemdup(orig->preplay_esn,
++ xfrm_replay_state_esn_len(orig->preplay_esn),
+ GFP_KERNEL);
+- if (!x->preplay_esn) {
+- kfree(x->replay_esn);
++ if (!x->preplay_esn)
+ return -ENOMEM;
+- }
+
+ return 0;
+ }
+diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
+index 4953e9994df34..8e174a24c5757 100644
+--- a/include/soc/mscc/ocelot.h
++++ b/include/soc/mscc/ocelot.h
+@@ -468,6 +468,7 @@ struct ocelot;
+
+ struct ocelot_ops {
+ int (*reset)(struct ocelot *ocelot);
++ u16 (*wm_enc)(u16 value);
+ };
+
+ struct ocelot_acl_block {
+diff --git a/kernel/bpf/sysfs_btf.c b/kernel/bpf/sysfs_btf.c
+index 3b495773de5ae..11b3380887fa0 100644
+--- a/kernel/bpf/sysfs_btf.c
++++ b/kernel/bpf/sysfs_btf.c
+@@ -30,15 +30,15 @@ static struct kobject *btf_kobj;
+
+ static int __init btf_vmlinux_init(void)
+ {
+- if (!__start_BTF)
++ bin_attr_btf_vmlinux.size = __stop_BTF - __start_BTF;
++
++ if (!__start_BTF || bin_attr_btf_vmlinux.size == 0)
+ return 0;
+
+ btf_kobj = kobject_create_and_add("btf", kernel_kobj);
+ if (!btf_kobj)
+ return -ENOMEM;
+
+- bin_attr_btf_vmlinux.size = __stop_BTF - __start_BTF;
+-
+ return sysfs_create_bin_file(btf_kobj, &bin_attr_btf_vmlinux);
+ }
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 94cead5a43e57..89b07db146763 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -5490,8 +5490,8 @@ static void scalar32_min_max_or(struct bpf_reg_state *dst_reg,
+ bool src_known = tnum_subreg_is_const(src_reg->var_off);
+ bool dst_known = tnum_subreg_is_const(dst_reg->var_off);
+ struct tnum var32_off = tnum_subreg(dst_reg->var_off);
+- s32 smin_val = src_reg->smin_value;
+- u32 umin_val = src_reg->umin_value;
++ s32 smin_val = src_reg->s32_min_value;
++ u32 umin_val = src_reg->u32_min_value;
+
+ /* Assuming scalar64_min_max_or will be called so it is safe
+ * to skip updating register for known case.
+@@ -5514,8 +5514,8 @@ static void scalar32_min_max_or(struct bpf_reg_state *dst_reg,
+ /* ORing two positives gives a positive, so safe to
+ * cast result into s64.
+ */
+- dst_reg->s32_min_value = dst_reg->umin_value;
+- dst_reg->s32_max_value = dst_reg->umax_value;
++ dst_reg->s32_min_value = dst_reg->u32_min_value;
++ dst_reg->s32_max_value = dst_reg->u32_max_value;
+ }
+ }
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 856d98c36f562..fd8cd00099dae 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -99,7 +99,7 @@ static void remote_function(void *data)
+ * retry due to any failures in smp_call_function_single(), such as if the
+ * task_cpu() goes offline concurrently.
+ *
+- * returns @func return value or -ESRCH when the process isn't running
++ * returns @func return value or -ESRCH or -ENXIO when the process isn't running
+ */
+ static int
+ task_function_call(struct task_struct *p, remote_function_f func, void *info)
+@@ -115,7 +115,8 @@ task_function_call(struct task_struct *p, remote_function_f func, void *info)
+ for (;;) {
+ ret = smp_call_function_single(task_cpu(p), remote_function,
+ &data, 1);
+- ret = !ret ? data.ret : -EAGAIN;
++ if (!ret)
++ ret = data.ret;
+
+ if (ret != -EAGAIN)
+ break;
+diff --git a/kernel/umh.c b/kernel/umh.c
+index 79f139a7ca03c..6aaf456d402d9 100644
+--- a/kernel/umh.c
++++ b/kernel/umh.c
+@@ -14,6 +14,7 @@
+ #include <linux/cred.h>
+ #include <linux/file.h>
+ #include <linux/fdtable.h>
++#include <linux/fs_struct.h>
+ #include <linux/workqueue.h>
+ #include <linux/security.h>
+ #include <linux/mount.h>
+@@ -75,6 +76,14 @@ static int call_usermodehelper_exec_async(void *data)
+ flush_signal_handlers(current, 1);
+ spin_unlock_irq(&current->sighand->siglock);
+
++ /*
++ * Initial kernel threads share ther FS with init, in order to
++ * get the init root directory. But we've now created a new
++ * thread that is going to execve a user process and has its own
++ * 'struct fs_struct'. Reset umask to the default.
++ */
++ current->fs->umask = 0022;
++
+ /*
+ * Our parent (unbound workqueue) runs with elevated scheduling
+ * priority. Avoid propagating that into the userspace child.
+diff --git a/lib/fonts/font_10x18.c b/lib/fonts/font_10x18.c
+index 532f0ff89a962..0e2deac97da0d 100644
+--- a/lib/fonts/font_10x18.c
++++ b/lib/fonts/font_10x18.c
+@@ -8,8 +8,8 @@
+
+ #define FONTDATAMAX 9216
+
+-static const unsigned char fontdata_10x18[FONTDATAMAX] = {
+-
++static struct font_data fontdata_10x18 = {
++ { 0, 0, FONTDATAMAX, 0 }, {
+ /* 0 0x00 '^@' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+@@ -5129,8 +5129,7 @@ static const unsigned char fontdata_10x18[FONTDATAMAX] = {
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+-
+-};
++} };
+
+
+ const struct font_desc font_10x18 = {
+@@ -5138,7 +5137,7 @@ const struct font_desc font_10x18 = {
+ .name = "10x18",
+ .width = 10,
+ .height = 18,
+- .data = fontdata_10x18,
++ .data = fontdata_10x18.data,
+ #ifdef __sparc__
+ .pref = 5,
+ #else
+diff --git a/lib/fonts/font_6x10.c b/lib/fonts/font_6x10.c
+index 09b2cc03435b9..87da8acd07db0 100644
+--- a/lib/fonts/font_6x10.c
++++ b/lib/fonts/font_6x10.c
+@@ -1,8 +1,10 @@
+ // SPDX-License-Identifier: GPL-2.0
+ #include <linux/font.h>
+
+-static const unsigned char fontdata_6x10[] = {
++#define FONTDATAMAX 2560
+
++static struct font_data fontdata_6x10 = {
++ { 0, 0, FONTDATAMAX, 0 }, {
+ /* 0 0x00 '^@' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+@@ -3074,14 +3076,13 @@ static const unsigned char fontdata_6x10[] = {
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+-
+-};
++} };
+
+ const struct font_desc font_6x10 = {
+ .idx = FONT6x10_IDX,
+ .name = "6x10",
+ .width = 6,
+ .height = 10,
+- .data = fontdata_6x10,
++ .data = fontdata_6x10.data,
+ .pref = 0,
+ };
+diff --git a/lib/fonts/font_6x11.c b/lib/fonts/font_6x11.c
+index d7136c33f1f01..5e975dfa10a53 100644
+--- a/lib/fonts/font_6x11.c
++++ b/lib/fonts/font_6x11.c
+@@ -9,8 +9,8 @@
+
+ #define FONTDATAMAX (11*256)
+
+-static const unsigned char fontdata_6x11[FONTDATAMAX] = {
+-
++static struct font_data fontdata_6x11 = {
++ { 0, 0, FONTDATAMAX, 0 }, {
+ /* 0 0x00 '^@' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+@@ -3338,8 +3338,7 @@ static const unsigned char fontdata_6x11[FONTDATAMAX] = {
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+-
+-};
++} };
+
+
+ const struct font_desc font_vga_6x11 = {
+@@ -3347,7 +3346,7 @@ const struct font_desc font_vga_6x11 = {
+ .name = "ProFont6x11",
+ .width = 6,
+ .height = 11,
+- .data = fontdata_6x11,
++ .data = fontdata_6x11.data,
+ /* Try avoiding this font if possible unless on MAC */
+ .pref = -2000,
+ };
+diff --git a/lib/fonts/font_7x14.c b/lib/fonts/font_7x14.c
+index 89752d0b23e8b..86d298f385058 100644
+--- a/lib/fonts/font_7x14.c
++++ b/lib/fonts/font_7x14.c
+@@ -8,8 +8,8 @@
+
+ #define FONTDATAMAX 3584
+
+-static const unsigned char fontdata_7x14[FONTDATAMAX] = {
+-
++static struct font_data fontdata_7x14 = {
++ { 0, 0, FONTDATAMAX, 0 }, {
+ /* 0 0x00 '^@' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+@@ -4105,8 +4105,7 @@ static const unsigned char fontdata_7x14[FONTDATAMAX] = {
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+-
+-};
++} };
+
+
+ const struct font_desc font_7x14 = {
+@@ -4114,6 +4113,6 @@ const struct font_desc font_7x14 = {
+ .name = "7x14",
+ .width = 7,
+ .height = 14,
+- .data = fontdata_7x14,
++ .data = fontdata_7x14.data,
+ .pref = 0,
+ };
+diff --git a/lib/fonts/font_8x16.c b/lib/fonts/font_8x16.c
+index b7ab1f5fbdb8a..37cedd36ca5ef 100644
+--- a/lib/fonts/font_8x16.c
++++ b/lib/fonts/font_8x16.c
+@@ -10,8 +10,8 @@
+
+ #define FONTDATAMAX 4096
+
+-static const unsigned char fontdata_8x16[FONTDATAMAX] = {
+-
++static struct font_data fontdata_8x16 = {
++ { 0, 0, FONTDATAMAX, 0 }, {
+ /* 0 0x00 '^@' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+@@ -4619,8 +4619,7 @@ static const unsigned char fontdata_8x16[FONTDATAMAX] = {
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+-
+-};
++} };
+
+
+ const struct font_desc font_vga_8x16 = {
+@@ -4628,7 +4627,7 @@ const struct font_desc font_vga_8x16 = {
+ .name = "VGA8x16",
+ .width = 8,
+ .height = 16,
+- .data = fontdata_8x16,
++ .data = fontdata_8x16.data,
+ .pref = 0,
+ };
+ EXPORT_SYMBOL(font_vga_8x16);
+diff --git a/lib/fonts/font_8x8.c b/lib/fonts/font_8x8.c
+index 2328ebc8bab5d..8ab695538395d 100644
+--- a/lib/fonts/font_8x8.c
++++ b/lib/fonts/font_8x8.c
+@@ -9,8 +9,8 @@
+
+ #define FONTDATAMAX 2048
+
+-static const unsigned char fontdata_8x8[FONTDATAMAX] = {
+-
++static struct font_data fontdata_8x8 = {
++ { 0, 0, FONTDATAMAX, 0 }, {
+ /* 0 0x00 '^@' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+@@ -2570,8 +2570,7 @@ static const unsigned char fontdata_8x8[FONTDATAMAX] = {
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+-
+-};
++} };
+
+
+ const struct font_desc font_vga_8x8 = {
+@@ -2579,6 +2578,6 @@ const struct font_desc font_vga_8x8 = {
+ .name = "VGA8x8",
+ .width = 8,
+ .height = 8,
+- .data = fontdata_8x8,
++ .data = fontdata_8x8.data,
+ .pref = 0,
+ };
+diff --git a/lib/fonts/font_acorn_8x8.c b/lib/fonts/font_acorn_8x8.c
+index 0ff0e85d4481b..069b3e80c4344 100644
+--- a/lib/fonts/font_acorn_8x8.c
++++ b/lib/fonts/font_acorn_8x8.c
+@@ -3,7 +3,10 @@
+
+ #include <linux/font.h>
+
+-static const unsigned char acorndata_8x8[] = {
++#define FONTDATAMAX 2048
++
++static struct font_data acorndata_8x8 = {
++{ 0, 0, FONTDATAMAX, 0 }, {
+ /* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^@ */
+ /* 01 */ 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, /* ^A */
+ /* 02 */ 0x7e, 0xff, 0xbd, 0xff, 0xc3, 0xe7, 0xff, 0x7e, /* ^B */
+@@ -260,14 +263,14 @@ static const unsigned char acorndata_8x8[] = {
+ /* FD */ 0x38, 0x04, 0x18, 0x20, 0x3c, 0x00, 0x00, 0x00,
+ /* FE */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+ /* FF */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+-};
++} };
+
+ const struct font_desc font_acorn_8x8 = {
+ .idx = ACORN8x8_IDX,
+ .name = "Acorn8x8",
+ .width = 8,
+ .height = 8,
+- .data = acorndata_8x8,
++ .data = acorndata_8x8.data,
+ #ifdef CONFIG_ARCH_ACORN
+ .pref = 20,
+ #else
+diff --git a/lib/fonts/font_mini_4x6.c b/lib/fonts/font_mini_4x6.c
+index 838caa1cfef70..1449876c6a270 100644
+--- a/lib/fonts/font_mini_4x6.c
++++ b/lib/fonts/font_mini_4x6.c
+@@ -43,8 +43,8 @@ __END__;
+
+ #define FONTDATAMAX 1536
+
+-static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = {
+-
++static struct font_data fontdata_mini_4x6 = {
++ { 0, 0, FONTDATAMAX, 0 }, {
+ /*{*/
+ /* Char 0: ' ' */
+ 0xee, /*= [*** ] */
+@@ -2145,14 +2145,14 @@ static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = {
+ 0xee, /*= [*** ] */
+ 0x00, /*= [ ] */
+ /*}*/
+-};
++} };
+
+ const struct font_desc font_mini_4x6 = {
+ .idx = MINI4x6_IDX,
+ .name = "MINI4x6",
+ .width = 4,
+ .height = 6,
+- .data = fontdata_mini_4x6,
++ .data = fontdata_mini_4x6.data,
+ .pref = 3,
+ };
+
+diff --git a/lib/fonts/font_pearl_8x8.c b/lib/fonts/font_pearl_8x8.c
+index b15d3c342c5bb..32d65551e7ed2 100644
+--- a/lib/fonts/font_pearl_8x8.c
++++ b/lib/fonts/font_pearl_8x8.c
+@@ -14,8 +14,8 @@
+
+ #define FONTDATAMAX 2048
+
+-static const unsigned char fontdata_pearl8x8[FONTDATAMAX] = {
+-
++static struct font_data fontdata_pearl8x8 = {
++ { 0, 0, FONTDATAMAX, 0 }, {
+ /* 0 0x00 '^@' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+@@ -2575,14 +2575,13 @@ static const unsigned char fontdata_pearl8x8[FONTDATAMAX] = {
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+-
+-};
++} };
+
+ const struct font_desc font_pearl_8x8 = {
+ .idx = PEARL8x8_IDX,
+ .name = "PEARL8x8",
+ .width = 8,
+ .height = 8,
+- .data = fontdata_pearl8x8,
++ .data = fontdata_pearl8x8.data,
+ .pref = 2,
+ };
+diff --git a/lib/fonts/font_sun12x22.c b/lib/fonts/font_sun12x22.c
+index 955d6eee3959d..641a6b4dca424 100644
+--- a/lib/fonts/font_sun12x22.c
++++ b/lib/fonts/font_sun12x22.c
+@@ -3,8 +3,8 @@
+
+ #define FONTDATAMAX 11264
+
+-static const unsigned char fontdata_sun12x22[FONTDATAMAX] = {
+-
++static struct font_data fontdata_sun12x22 = {
++ { 0, 0, FONTDATAMAX, 0 }, {
+ /* 0 0x00 '^@' */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+@@ -6148,8 +6148,7 @@ static const unsigned char fontdata_sun12x22[FONTDATAMAX] = {
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+-
+-};
++} };
+
+
+ const struct font_desc font_sun_12x22 = {
+@@ -6157,7 +6156,7 @@ const struct font_desc font_sun_12x22 = {
+ .name = "SUN12x22",
+ .width = 12,
+ .height = 22,
+- .data = fontdata_sun12x22,
++ .data = fontdata_sun12x22.data,
+ #ifdef __sparc__
+ .pref = 5,
+ #else
+diff --git a/lib/fonts/font_sun8x16.c b/lib/fonts/font_sun8x16.c
+index 03d71e53954ab..193fe6d988e08 100644
+--- a/lib/fonts/font_sun8x16.c
++++ b/lib/fonts/font_sun8x16.c
+@@ -3,7 +3,8 @@
+
+ #define FONTDATAMAX 4096
+
+-static const unsigned char fontdata_sun8x16[FONTDATAMAX] = {
++static struct font_data fontdata_sun8x16 = {
++{ 0, 0, FONTDATAMAX, 0 }, {
+ /* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ /* */ 0x00,0x00,0x7e,0x81,0xa5,0x81,0x81,0xbd,0x99,0x81,0x81,0x7e,0x00,0x00,0x00,0x00,
+ /* */ 0x00,0x00,0x7e,0xff,0xdb,0xff,0xff,0xc3,0xe7,0xff,0xff,0x7e,0x00,0x00,0x00,0x00,
+@@ -260,14 +261,14 @@ static const unsigned char fontdata_sun8x16[FONTDATAMAX] = {
+ /* */ 0x00,0x70,0xd8,0x30,0x60,0xc8,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ /* */ 0x00,0x00,0x00,0x00,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x00,0x00,0x00,0x00,0x00,
+ /* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+-};
++} };
+
+ const struct font_desc font_sun_8x16 = {
+ .idx = SUN8x16_IDX,
+ .name = "SUN8x16",
+ .width = 8,
+ .height = 16,
+- .data = fontdata_sun8x16,
++ .data = fontdata_sun8x16.data,
+ #ifdef __sparc__
+ .pref = 10,
+ #else
+diff --git a/lib/fonts/font_ter16x32.c b/lib/fonts/font_ter16x32.c
+index 3f0cf1ccdf3a4..91b9c283bd9cc 100644
+--- a/lib/fonts/font_ter16x32.c
++++ b/lib/fonts/font_ter16x32.c
+@@ -4,8 +4,8 @@
+
+ #define FONTDATAMAX 16384
+
+-static const unsigned char fontdata_ter16x32[FONTDATAMAX] = {
+-
++static struct font_data fontdata_ter16x32 = {
++ { 0, 0, FONTDATAMAX, 0 }, {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x7f, 0xfc,
+ 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
+@@ -2054,8 +2054,7 @@ static const unsigned char fontdata_ter16x32[FONTDATAMAX] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 255 */
+-
+-};
++} };
+
+
+ const struct font_desc font_ter_16x32 = {
+@@ -2063,7 +2062,7 @@ const struct font_desc font_ter_16x32 = {
+ .name = "TER16x32",
+ .width = 16,
+ .height = 32,
+- .data = fontdata_ter16x32,
++ .data = fontdata_ter16x32.data,
+ #ifdef __sparc__
+ .pref = 5,
+ #else
+diff --git a/mm/khugepaged.c b/mm/khugepaged.c
+index e6fc7c3e7dc98..bc2812bb1a010 100644
+--- a/mm/khugepaged.c
++++ b/mm/khugepaged.c
+@@ -56,6 +56,9 @@ enum scan_result {
+ #define CREATE_TRACE_POINTS
+ #include <trace/events/huge_memory.h>
+
++static struct task_struct *khugepaged_thread __read_mostly;
++static DEFINE_MUTEX(khugepaged_mutex);
++
+ /* default scan 8*512 pte (or vmas) every 30 second */
+ static unsigned int khugepaged_pages_to_scan __read_mostly;
+ static unsigned int khugepaged_pages_collapsed;
+@@ -914,6 +917,18 @@ static struct page *khugepaged_alloc_hugepage(bool *wait)
+
+ static bool khugepaged_prealloc_page(struct page **hpage, bool *wait)
+ {
++ /*
++ * If the hpage allocated earlier was briefly exposed in page cache
++ * before collapse_file() failed, it is possible that racing lookups
++ * have not yet completed, and would then be unpleasantly surprised by
++ * finding the hpage reused for the same mapping at a different offset.
++ * Just release the previous allocation if there is any danger of that.
++ */
++ if (*hpage && page_count(*hpage) > 1) {
++ put_page(*hpage);
++ *hpage = NULL;
++ }
++
+ if (!*hpage)
+ *hpage = khugepaged_alloc_hugepage(wait);
+
+@@ -2292,8 +2307,6 @@ static void set_recommended_min_free_kbytes(void)
+
+ int start_stop_khugepaged(void)
+ {
+- static struct task_struct *khugepaged_thread __read_mostly;
+- static DEFINE_MUTEX(khugepaged_mutex);
+ int err = 0;
+
+ mutex_lock(&khugepaged_mutex);
+@@ -2320,3 +2333,11 @@ fail:
+ mutex_unlock(&khugepaged_mutex);
+ return err;
+ }
++
++void khugepaged_min_free_kbytes_update(void)
++{
++ mutex_lock(&khugepaged_mutex);
++ if (khugepaged_enabled() && khugepaged_thread)
++ set_recommended_min_free_kbytes();
++ mutex_unlock(&khugepaged_mutex);
++}
+diff --git a/mm/page_alloc.c b/mm/page_alloc.c
+index 898ff44f2c7b2..43f6d91f57156 100644
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -69,6 +69,7 @@
+ #include <linux/nmi.h>
+ #include <linux/psi.h>
+ #include <linux/padata.h>
++#include <linux/khugepaged.h>
+
+ #include <asm/sections.h>
+ #include <asm/tlbflush.h>
+@@ -7884,6 +7885,8 @@ int __meminit init_per_zone_wmark_min(void)
+ setup_min_slab_ratio();
+ #endif
+
++ khugepaged_min_free_kbytes_update();
++
+ return 0;
+ }
+ postcore_initcall(init_per_zone_wmark_min)
+diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
+index 4877a0db16c66..a8fa622e2d9b4 100644
+--- a/net/bridge/br_fdb.c
++++ b/net/bridge/br_fdb.c
+@@ -404,6 +404,8 @@ void br_fdb_delete_by_port(struct net_bridge *br,
+
+ if (!do_all)
+ if (test_bit(BR_FDB_STATIC, &f->flags) ||
++ (test_bit(BR_FDB_ADDED_BY_EXT_LEARN, &f->flags) &&
++ !test_bit(BR_FDB_OFFLOADED, &f->flags)) ||
+ (vid && f->key.vlan_id != vid))
+ continue;
+
+diff --git a/net/core/skbuff.c b/net/core/skbuff.c
+index c50bd7a7943ab..72f4a3730ecf0 100644
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -5621,7 +5621,7 @@ int skb_mpls_push(struct sk_buff *skb, __be32 mpls_lse, __be16 mpls_proto,
+ lse->label_stack_entry = mpls_lse;
+ skb_postpush_rcsum(skb, lse, MPLS_HLEN);
+
+- if (ethernet)
++ if (ethernet && mac_len >= ETH_HLEN)
+ skb_mod_eth_type(skb, eth_hdr(skb), mpls_proto);
+ skb->protocol = mpls_proto;
+
+@@ -5661,7 +5661,7 @@ int skb_mpls_pop(struct sk_buff *skb, __be16 next_proto, int mac_len,
+ skb_reset_mac_header(skb);
+ skb_set_network_header(skb, mac_len);
+
+- if (ethernet) {
++ if (ethernet && mac_len >= ETH_HLEN) {
+ struct ethhdr *hdr;
+
+ /* use mpls_hdr() to get ethertype to account for VLANs. */
+diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
+index 30c1142584b1a..06a8242aa6980 100644
+--- a/net/ipv4/tcp.c
++++ b/net/ipv4/tcp.c
+@@ -970,7 +970,8 @@ ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
+ long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
+
+ if (IS_ENABLED(CONFIG_DEBUG_VM) &&
+- WARN_ONCE(PageSlab(page), "page must not be a Slab one"))
++ WARN_ONCE(!sendpage_ok(page),
++ "page must not be a Slab one and have page_count > 0"))
+ return -EINVAL;
+
+ /* Wait for a connection to finish. One exception is TCP Fast Open
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index 04bfcbbfee83a..ab4576ac1fe6e 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -1787,12 +1787,12 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb)
+
+ __skb_pull(skb, hdrlen);
+ if (skb_try_coalesce(tail, skb, &fragstolen, &delta)) {
+- thtail->window = th->window;
+-
+ TCP_SKB_CB(tail)->end_seq = TCP_SKB_CB(skb)->end_seq;
+
+- if (after(TCP_SKB_CB(skb)->ack_seq, TCP_SKB_CB(tail)->ack_seq))
++ if (likely(!before(TCP_SKB_CB(skb)->ack_seq, TCP_SKB_CB(tail)->ack_seq))) {
+ TCP_SKB_CB(tail)->ack_seq = TCP_SKB_CB(skb)->ack_seq;
++ thtail->window = th->window;
++ }
+
+ /* We have to update both TCP_SKB_CB(tail)->tcp_flags and
+ * thtail->fin, so that the fast path in tcp_rcv_established()
+diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
+index 9395ee8a868db..a4148ef314ea2 100644
+--- a/net/netlink/genetlink.c
++++ b/net/netlink/genetlink.c
+@@ -1079,7 +1079,7 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
+ if (err)
+ return err;
+
+- while (netlink_policy_dump_loop(&cb->args[1])) {
++ while (netlink_policy_dump_loop(cb->args[1])) {
+ void *hdr;
+ struct nlattr *nest;
+
+@@ -1113,6 +1113,12 @@ nla_put_failure:
+ return skb->len;
+ }
+
++static int ctrl_dumppolicy_done(struct netlink_callback *cb)
++{
++ netlink_policy_dump_free(cb->args[1]);
++ return 0;
++}
++
+ static const struct genl_ops genl_ctrl_ops[] = {
+ {
+ .cmd = CTRL_CMD_GETFAMILY,
+@@ -1123,6 +1129,7 @@ static const struct genl_ops genl_ctrl_ops[] = {
+ {
+ .cmd = CTRL_CMD_GETPOLICY,
+ .dumpit = ctrl_dumppolicy,
++ .done = ctrl_dumppolicy_done,
+ },
+ };
+
+diff --git a/net/netlink/policy.c b/net/netlink/policy.c
+index 2b3e26f7496f5..ceeaee157b2f6 100644
+--- a/net/netlink/policy.c
++++ b/net/netlink/policy.c
+@@ -84,7 +84,6 @@ int netlink_policy_dump_start(const struct nla_policy *policy,
+ unsigned int policy_idx;
+ int err;
+
+- /* also returns 0 if "*_state" is our ERR_PTR() end marker */
+ if (*_state)
+ return 0;
+
+@@ -140,21 +139,11 @@ static bool netlink_policy_dump_finished(struct nl_policy_dump *state)
+ !state->policies[state->policy_idx].policy;
+ }
+
+-bool netlink_policy_dump_loop(unsigned long *_state)
++bool netlink_policy_dump_loop(unsigned long _state)
+ {
+- struct nl_policy_dump *state = (void *)*_state;
+-
+- if (IS_ERR(state))
+- return false;
+-
+- if (netlink_policy_dump_finished(state)) {
+- kfree(state);
+- /* store end marker instead of freed state */
+- *_state = (unsigned long)ERR_PTR(-ENOENT);
+- return false;
+- }
++ struct nl_policy_dump *state = (void *)_state;
+
+- return true;
++ return !netlink_policy_dump_finished(state);
+ }
+
+ int netlink_policy_dump_write(struct sk_buff *skb, unsigned long _state)
+@@ -309,3 +298,10 @@ nla_put_failure:
+ nla_nest_cancel(skb, policy);
+ return -ENOBUFS;
+ }
++
++void netlink_policy_dump_free(unsigned long _state)
++{
++ struct nl_policy_dump *state = (void *)_state;
++
++ kfree(state);
++}
+diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c
+index 4340f25fe390f..67dacc7152f75 100644
+--- a/net/openvswitch/conntrack.c
++++ b/net/openvswitch/conntrack.c
+@@ -903,15 +903,19 @@ static int ovs_ct_nat(struct net *net, struct sw_flow_key *key,
+ }
+ err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, maniptype);
+
+- if (err == NF_ACCEPT &&
+- ct->status & IPS_SRC_NAT && ct->status & IPS_DST_NAT) {
+- if (maniptype == NF_NAT_MANIP_SRC)
+- maniptype = NF_NAT_MANIP_DST;
+- else
+- maniptype = NF_NAT_MANIP_SRC;
+-
+- err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range,
+- maniptype);
++ if (err == NF_ACCEPT && ct->status & IPS_DST_NAT) {
++ if (ct->status & IPS_SRC_NAT) {
++ if (maniptype == NF_NAT_MANIP_SRC)
++ maniptype = NF_NAT_MANIP_DST;
++ else
++ maniptype = NF_NAT_MANIP_SRC;
++
++ err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range,
++ maniptype);
++ } else if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
++ err = ovs_ct_nat_execute(skb, ct, ctinfo, NULL,
++ NF_NAT_MANIP_SRC);
++ }
+ }
+
+ /* Mark NAT done if successful and update the flow key. */
+diff --git a/net/qrtr/ns.c b/net/qrtr/ns.c
+index d8252fdab851a..934999b56d60a 100644
+--- a/net/qrtr/ns.c
++++ b/net/qrtr/ns.c
+@@ -193,12 +193,13 @@ static int announce_servers(struct sockaddr_qrtr *sq)
+ struct qrtr_server *srv;
+ struct qrtr_node *node;
+ void __rcu **slot;
+- int ret;
++ int ret = 0;
+
+ node = node_get(qrtr_ns.local_node);
+ if (!node)
+ return 0;
+
++ rcu_read_lock();
+ /* Announce the list of servers registered in this node */
+ radix_tree_for_each_slot(slot, &node->servers, &iter, 0) {
+ srv = radix_tree_deref_slot(slot);
+@@ -206,11 +207,14 @@ static int announce_servers(struct sockaddr_qrtr *sq)
+ ret = service_announce_new(sq, srv);
+ if (ret < 0) {
+ pr_err("failed to announce new service\n");
+- return ret;
++ goto err_out;
+ }
+ }
+
+- return 0;
++err_out:
++ rcu_read_unlock();
++
++ return ret;
+ }
+
+ static struct qrtr_server *server_add(unsigned int service,
+@@ -335,7 +339,7 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
+ struct qrtr_node *node;
+ void __rcu **slot;
+ struct kvec iv;
+- int ret;
++ int ret = 0;
+
+ iv.iov_base = &pkt;
+ iv.iov_len = sizeof(pkt);
+@@ -344,11 +348,13 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
+ if (!node)
+ return 0;
+
++ rcu_read_lock();
+ /* Advertise removal of this client to all servers of remote node */
+ radix_tree_for_each_slot(slot, &node->servers, &iter, 0) {
+ srv = radix_tree_deref_slot(slot);
+ server_del(node, srv->port);
+ }
++ rcu_read_unlock();
+
+ /* Advertise the removal of this client to all local servers */
+ local_node = node_get(qrtr_ns.local_node);
+@@ -359,6 +365,7 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
+ pkt.cmd = cpu_to_le32(QRTR_TYPE_BYE);
+ pkt.client.node = cpu_to_le32(from->sq_node);
+
++ rcu_read_lock();
+ radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) {
+ srv = radix_tree_deref_slot(slot);
+
+@@ -372,11 +379,14 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
+ ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt));
+ if (ret < 0) {
+ pr_err("failed to send bye cmd\n");
+- return ret;
++ goto err_out;
+ }
+ }
+
+- return 0;
++err_out:
++ rcu_read_unlock();
++
++ return ret;
+ }
+
+ static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
+@@ -394,7 +404,7 @@ static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
+ struct list_head *li;
+ void __rcu **slot;
+ struct kvec iv;
+- int ret;
++ int ret = 0;
+
+ iv.iov_base = &pkt;
+ iv.iov_len = sizeof(pkt);
+@@ -434,6 +444,7 @@ static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
+ pkt.client.node = cpu_to_le32(node_id);
+ pkt.client.port = cpu_to_le32(port);
+
++ rcu_read_lock();
+ radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) {
+ srv = radix_tree_deref_slot(slot);
+
+@@ -447,11 +458,14 @@ static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
+ ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt));
+ if (ret < 0) {
+ pr_err("failed to send del client cmd\n");
+- return ret;
++ goto err_out;
+ }
+ }
+
+- return 0;
++err_out:
++ rcu_read_unlock();
++
++ return ret;
+ }
+
+ static int ctrl_cmd_new_server(struct sockaddr_qrtr *from,
+@@ -554,6 +568,7 @@ static int ctrl_cmd_new_lookup(struct sockaddr_qrtr *from,
+ filter.service = service;
+ filter.instance = instance;
+
++ rcu_read_lock();
+ radix_tree_for_each_slot(node_slot, &nodes, &node_iter, 0) {
+ node = radix_tree_deref_slot(node_slot);
+
+@@ -568,6 +583,7 @@ static int ctrl_cmd_new_lookup(struct sockaddr_qrtr *from,
+ lookup_notify(from, srv, true);
+ }
+ }
++ rcu_read_unlock();
+
+ /* Empty notification, to indicate end of listing */
+ lookup_notify(from, NULL, true);
+diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c
+index 447f55ca68860..6e972b4823efa 100644
+--- a/net/rxrpc/conn_event.c
++++ b/net/rxrpc/conn_event.c
+@@ -340,18 +340,18 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
+ return ret;
+
+ spin_lock(&conn->channel_lock);
+- spin_lock(&conn->state_lock);
++ spin_lock_bh(&conn->state_lock);
+
+ if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) {
+ conn->state = RXRPC_CONN_SERVICE;
+- spin_unlock(&conn->state_lock);
++ spin_unlock_bh(&conn->state_lock);
+ for (loop = 0; loop < RXRPC_MAXCALLS; loop++)
+ rxrpc_call_is_secure(
+ rcu_dereference_protected(
+ conn->channels[loop].call,
+ lockdep_is_held(&conn->channel_lock)));
+ } else {
+- spin_unlock(&conn->state_lock);
++ spin_unlock_bh(&conn->state_lock);
+ }
+
+ spin_unlock(&conn->channel_lock);
+diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c
+index 0c98313dd7a8c..85a9ff8cd236a 100644
+--- a/net/rxrpc/key.c
++++ b/net/rxrpc/key.c
+@@ -903,7 +903,7 @@ int rxrpc_request_key(struct rxrpc_sock *rx, char __user *optval, int optlen)
+
+ _enter("");
+
+- if (optlen <= 0 || optlen > PAGE_SIZE - 1)
++ if (optlen <= 0 || optlen > PAGE_SIZE - 1 || rx->securities)
+ return -EINVAL;
+
+ description = memdup_user_nul(optval, optlen);
+@@ -941,7 +941,7 @@ int rxrpc_server_keyring(struct rxrpc_sock *rx, char __user *optval,
+ if (IS_ERR(description))
+ return PTR_ERR(description);
+
+- key = request_key_net(&key_type_keyring, description, sock_net(&rx->sk), NULL);
++ key = request_key(&key_type_keyring, description, NULL);
+ if (IS_ERR(key)) {
+ kfree(description);
+ _leave(" = %ld", PTR_ERR(key));
+@@ -1073,7 +1073,7 @@ static long rxrpc_read(const struct key *key,
+
+ switch (token->security_index) {
+ case RXRPC_SECURITY_RXKAD:
+- toksize += 9 * 4; /* viceid, kvno, key*2 + len, begin,
++ toksize += 8 * 4; /* viceid, kvno, key*2, begin,
+ * end, primary, tktlen */
+ toksize += RND(token->kad->ticket_len);
+ break;
+@@ -1108,7 +1108,8 @@ static long rxrpc_read(const struct key *key,
+ break;
+
+ default: /* we have a ticket we can't encode */
+- BUG();
++ pr_err("Unsupported key token type (%u)\n",
++ token->security_index);
+ continue;
+ }
+
+@@ -1139,6 +1140,14 @@ static long rxrpc_read(const struct key *key,
+ memcpy((u8 *)xdr + _l, &zero, 4 - (_l & 3)); \
+ xdr += (_l + 3) >> 2; \
+ } while(0)
++#define ENCODE_BYTES(l, s) \
++ do { \
++ u32 _l = (l); \
++ memcpy(xdr, (s), _l); \
++ if (_l & 3) \
++ memcpy((u8 *)xdr + _l, &zero, 4 - (_l & 3)); \
++ xdr += (_l + 3) >> 2; \
++ } while(0)
+ #define ENCODE64(x) \
+ do { \
+ __be64 y = cpu_to_be64(x); \
+@@ -1166,7 +1175,7 @@ static long rxrpc_read(const struct key *key,
+ case RXRPC_SECURITY_RXKAD:
+ ENCODE(token->kad->vice_id);
+ ENCODE(token->kad->kvno);
+- ENCODE_DATA(8, token->kad->session_key);
++ ENCODE_BYTES(8, token->kad->session_key);
+ ENCODE(token->kad->start);
+ ENCODE(token->kad->expiry);
+ ENCODE(token->kad->primary_flag);
+@@ -1216,7 +1225,6 @@ static long rxrpc_read(const struct key *key,
+ break;
+
+ default:
+- BUG();
+ break;
+ }
+
+diff --git a/net/sched/act_api.c b/net/sched/act_api.c
+index 8ac7eb0a83096..aa69fc4ce39d9 100644
+--- a/net/sched/act_api.c
++++ b/net/sched/act_api.c
+@@ -307,6 +307,8 @@ static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
+
+ mutex_lock(&idrinfo->lock);
+ idr_for_each_entry_ul(idr, p, tmp, id) {
++ if (IS_ERR(p))
++ continue;
+ ret = tcf_idr_release_unsafe(p);
+ if (ret == ACT_P_DELETED) {
+ module_put(ops->owner);
+@@ -467,17 +469,6 @@ int tcf_idr_create_from_flags(struct tc_action_net *tn, u32 index,
+ }
+ EXPORT_SYMBOL(tcf_idr_create_from_flags);
+
+-void tcf_idr_insert(struct tc_action_net *tn, struct tc_action *a)
+-{
+- struct tcf_idrinfo *idrinfo = tn->idrinfo;
+-
+- mutex_lock(&idrinfo->lock);
+- /* Replace ERR_PTR(-EBUSY) allocated by tcf_idr_check_alloc */
+- WARN_ON(!IS_ERR(idr_replace(&idrinfo->action_idr, a, a->tcfa_index)));
+- mutex_unlock(&idrinfo->lock);
+-}
+-EXPORT_SYMBOL(tcf_idr_insert);
+-
+ /* Cleanup idr index that was allocated but not initialized. */
+
+ void tcf_idr_cleanup(struct tc_action_net *tn, u32 index)
+@@ -902,6 +893,26 @@ static const struct nla_policy tcf_action_policy[TCA_ACT_MAX + 1] = {
+ [TCA_ACT_HW_STATS] = NLA_POLICY_BITFIELD32(TCA_ACT_HW_STATS_ANY),
+ };
+
++static void tcf_idr_insert_many(struct tc_action *actions[])
++{
++ int i;
++
++ for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
++ struct tc_action *a = actions[i];
++ struct tcf_idrinfo *idrinfo;
++
++ if (!a)
++ continue;
++ idrinfo = a->idrinfo;
++ mutex_lock(&idrinfo->lock);
++ /* Replace ERR_PTR(-EBUSY) allocated by tcf_idr_check_alloc if
++ * it is just created, otherwise this is just a nop.
++ */
++ idr_replace(&idrinfo->action_idr, a, a->tcfa_index);
++ mutex_unlock(&idrinfo->lock);
++ }
++}
++
+ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
+ struct nlattr *nla, struct nlattr *est,
+ char *name, int ovr, int bind,
+@@ -989,6 +1000,13 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
+ if (err < 0)
+ goto err_mod;
+
++ if (TC_ACT_EXT_CMP(a->tcfa_action, TC_ACT_GOTO_CHAIN) &&
++ !rcu_access_pointer(a->goto_chain)) {
++ tcf_action_destroy_1(a, bind);
++ NL_SET_ERR_MSG(extack, "can't use goto chain with NULL chain");
++ return ERR_PTR(-EINVAL);
++ }
++
+ if (!name && tb[TCA_ACT_COOKIE])
+ tcf_set_action_cookie(&a->act_cookie, cookie);
+
+@@ -1002,13 +1020,6 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
+ if (err != ACT_P_CREATED)
+ module_put(a_o->owner);
+
+- if (TC_ACT_EXT_CMP(a->tcfa_action, TC_ACT_GOTO_CHAIN) &&
+- !rcu_access_pointer(a->goto_chain)) {
+- tcf_action_destroy_1(a, bind);
+- NL_SET_ERR_MSG(extack, "can't use goto chain with NULL chain");
+- return ERR_PTR(-EINVAL);
+- }
+-
+ return a;
+
+ err_mod:
+@@ -1051,6 +1062,11 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
+ actions[i - 1] = act;
+ }
+
++ /* We have to commit them all together, because if any error happened in
++ * between, we could not handle the failure gracefully.
++ */
++ tcf_idr_insert_many(actions);
++
+ *attr_size = tcf_action_full_attrs_size(sz);
+ return i - 1;
+
+diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c
+index 54d5652cfe6ca..a4c7ba35a3438 100644
+--- a/net/sched/act_bpf.c
++++ b/net/sched/act_bpf.c
+@@ -365,9 +365,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
+ if (goto_ch)
+ tcf_chain_put_by_act(goto_ch);
+
+- if (res == ACT_P_CREATED) {
+- tcf_idr_insert(tn, *act);
+- } else {
++ if (res != ACT_P_CREATED) {
+ /* make sure the program being replaced is no longer executing */
+ synchronize_rcu();
+ tcf_bpf_cfg_cleanup(&old);
+diff --git a/net/sched/act_connmark.c b/net/sched/act_connmark.c
+index f901421b0634d..e19885d7fe2cb 100644
+--- a/net/sched/act_connmark.c
++++ b/net/sched/act_connmark.c
+@@ -139,7 +139,6 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
+ ci->net = net;
+ ci->zone = parm->zone;
+
+- tcf_idr_insert(tn, *a);
+ ret = ACT_P_CREATED;
+ } else if (ret > 0) {
+ ci = to_connmark(*a);
+diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c
+index c60674cf25c4f..8b3f45cdc319d 100644
+--- a/net/sched/act_csum.c
++++ b/net/sched/act_csum.c
+@@ -110,9 +110,6 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla,
+ if (params_new)
+ kfree_rcu(params_new, rcu);
+
+- if (ret == ACT_P_CREATED)
+- tcf_idr_insert(tn, *a);
+-
+ return ret;
+ put_chain:
+ if (goto_ch)
+diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c
+index 41d8440deaf14..0eb4722cf7cd9 100644
+--- a/net/sched/act_ct.c
++++ b/net/sched/act_ct.c
+@@ -1293,8 +1293,6 @@ static int tcf_ct_init(struct net *net, struct nlattr *nla,
+ tcf_chain_put_by_act(goto_ch);
+ if (params)
+ call_rcu(&params->rcu, tcf_ct_params_free);
+- if (res == ACT_P_CREATED)
+- tcf_idr_insert(tn, *a);
+
+ return res;
+
+diff --git a/net/sched/act_ctinfo.c b/net/sched/act_ctinfo.c
+index b5042f3ea079e..6084300e51adb 100644
+--- a/net/sched/act_ctinfo.c
++++ b/net/sched/act_ctinfo.c
+@@ -269,9 +269,6 @@ static int tcf_ctinfo_init(struct net *net, struct nlattr *nla,
+ if (cp_new)
+ kfree_rcu(cp_new, rcu);
+
+- if (ret == ACT_P_CREATED)
+- tcf_idr_insert(tn, *a);
+-
+ return ret;
+
+ put_chain:
+diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c
+index 4160657727196..1a29751ae63b5 100644
+--- a/net/sched/act_gact.c
++++ b/net/sched/act_gact.c
+@@ -140,8 +140,6 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
+ if (goto_ch)
+ tcf_chain_put_by_act(goto_ch);
+
+- if (ret == ACT_P_CREATED)
+- tcf_idr_insert(tn, *a);
+ return ret;
+ release_idr:
+ tcf_idr_release(*a, bind);
+diff --git a/net/sched/act_gate.c b/net/sched/act_gate.c
+index 323ae7f6315d4..c86e7fa7b2208 100644
+--- a/net/sched/act_gate.c
++++ b/net/sched/act_gate.c
+@@ -437,9 +437,6 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
+ if (goto_ch)
+ tcf_chain_put_by_act(goto_ch);
+
+- if (ret == ACT_P_CREATED)
+- tcf_idr_insert(tn, *a);
+-
+ return ret;
+
+ chain_put:
+diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c
+index 5c568757643b2..a2ddea04183af 100644
+--- a/net/sched/act_ife.c
++++ b/net/sched/act_ife.c
+@@ -627,9 +627,6 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
+ if (p)
+ kfree_rcu(p, rcu);
+
+- if (ret == ACT_P_CREATED)
+- tcf_idr_insert(tn, *a);
+-
+ return ret;
+ metadata_parse_err:
+ if (goto_ch)
+diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
+index 400a2cfe84522..8dc3bec0d3258 100644
+--- a/net/sched/act_ipt.c
++++ b/net/sched/act_ipt.c
+@@ -189,8 +189,6 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla,
+ ipt->tcfi_t = t;
+ ipt->tcfi_hook = hook;
+ spin_unlock_bh(&ipt->tcf_lock);
+- if (ret == ACT_P_CREATED)
+- tcf_idr_insert(tn, *a);
+ return ret;
+
+ err3:
+diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
+index 83dd82fc9f40c..cd3a7f814fc8c 100644
+--- a/net/sched/act_mirred.c
++++ b/net/sched/act_mirred.c
+@@ -194,8 +194,6 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
+ spin_lock(&mirred_list_lock);
+ list_add(&m->tcfm_list, &mirred_list);
+ spin_unlock(&mirred_list_lock);
+-
+- tcf_idr_insert(tn, *a);
+ }
+
+ return ret;
+diff --git a/net/sched/act_mpls.c b/net/sched/act_mpls.c
+index 8118e26409796..e298ec3b3c9e3 100644
+--- a/net/sched/act_mpls.c
++++ b/net/sched/act_mpls.c
+@@ -273,8 +273,6 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla,
+ if (p)
+ kfree_rcu(p, rcu);
+
+- if (ret == ACT_P_CREATED)
+- tcf_idr_insert(tn, *a);
+ return ret;
+ put_chain:
+ if (goto_ch)
+diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c
+index 855a6fa16a621..1ebd2a86d980f 100644
+--- a/net/sched/act_nat.c
++++ b/net/sched/act_nat.c
+@@ -93,9 +93,6 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
+ if (goto_ch)
+ tcf_chain_put_by_act(goto_ch);
+
+- if (ret == ACT_P_CREATED)
+- tcf_idr_insert(tn, *a);
+-
+ return ret;
+ release_idr:
+ tcf_idr_release(*a, bind);
+diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
+index d41d6200d9dec..ed1700fe662e1 100644
+--- a/net/sched/act_pedit.c
++++ b/net/sched/act_pedit.c
+@@ -238,8 +238,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
+ spin_unlock_bh(&p->tcf_lock);
+ if (goto_ch)
+ tcf_chain_put_by_act(goto_ch);
+- if (ret == ACT_P_CREATED)
+- tcf_idr_insert(tn, *a);
+ return ret;
+
+ put_chain:
+diff --git a/net/sched/act_police.c b/net/sched/act_police.c
+index 8b7a0ac96c516..2d236b9a411f0 100644
+--- a/net/sched/act_police.c
++++ b/net/sched/act_police.c
+@@ -201,8 +201,6 @@ static int tcf_police_init(struct net *net, struct nlattr *nla,
+ if (new)
+ kfree_rcu(new, rcu);
+
+- if (ret == ACT_P_CREATED)
+- tcf_idr_insert(tn, *a);
+ return ret;
+
+ failure:
+diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c
+index 5e2df590bb58a..3ebf9ede3cf10 100644
+--- a/net/sched/act_sample.c
++++ b/net/sched/act_sample.c
+@@ -116,8 +116,6 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
+ if (goto_ch)
+ tcf_chain_put_by_act(goto_ch);
+
+- if (ret == ACT_P_CREATED)
+- tcf_idr_insert(tn, *a);
+ return ret;
+ put_chain:
+ if (goto_ch)
+diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c
+index 9813ca4006dd1..a4f3d0f0daa96 100644
+--- a/net/sched/act_simple.c
++++ b/net/sched/act_simple.c
+@@ -157,8 +157,6 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
+ goto release_idr;
+ }
+
+- if (ret == ACT_P_CREATED)
+- tcf_idr_insert(tn, *a);
+ return ret;
+ put_chain:
+ if (goto_ch)
+diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
+index b2b3faa57294c..8012ae84847b8 100644
+--- a/net/sched/act_skbedit.c
++++ b/net/sched/act_skbedit.c
+@@ -224,8 +224,6 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
+ if (goto_ch)
+ tcf_chain_put_by_act(goto_ch);
+
+- if (ret == ACT_P_CREATED)
+- tcf_idr_insert(tn, *a);
+ return ret;
+ put_chain:
+ if (goto_ch)
+diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c
+index 39e6d94cfafbf..81a1c67335be6 100644
+--- a/net/sched/act_skbmod.c
++++ b/net/sched/act_skbmod.c
+@@ -190,8 +190,6 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
+ if (goto_ch)
+ tcf_chain_put_by_act(goto_ch);
+
+- if (ret == ACT_P_CREATED)
+- tcf_idr_insert(tn, *a);
+ return ret;
+ put_chain:
+ if (goto_ch)
+diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c
+index 536c4bc31be60..23cf8469a2e7c 100644
+--- a/net/sched/act_tunnel_key.c
++++ b/net/sched/act_tunnel_key.c
+@@ -536,9 +536,6 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
+ if (goto_ch)
+ tcf_chain_put_by_act(goto_ch);
+
+- if (ret == ACT_P_CREATED)
+- tcf_idr_insert(tn, *a);
+-
+ return ret;
+
+ put_chain:
+diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c
+index c91d3958fcbb8..68137d7519d01 100644
+--- a/net/sched/act_vlan.c
++++ b/net/sched/act_vlan.c
+@@ -229,8 +229,6 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
+ if (p)
+ kfree_rcu(p, rcu);
+
+- if (ret == ACT_P_CREATED)
+- tcf_idr_insert(tn, *a);
+ return ret;
+ put_chain:
+ if (goto_ch)
+diff --git a/net/sctp/auth.c b/net/sctp/auth.c
+index 83e97e8892e05..155aac6943d1b 100644
+--- a/net/sctp/auth.c
++++ b/net/sctp/auth.c
+@@ -494,6 +494,7 @@ int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp)
+ out_err:
+ /* Clean up any successful allocations */
+ sctp_auth_destroy_hmacs(ep->auth_hmacs);
++ ep->auth_hmacs = NULL;
+ return -ENOMEM;
+ }
+
+diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
+index 24f64bc0de18c..d8bc02b185f32 100644
+--- a/net/tls/tls_sw.c
++++ b/net/tls/tls_sw.c
+@@ -2142,10 +2142,15 @@ void tls_sw_release_resources_tx(struct sock *sk)
+ struct tls_context *tls_ctx = tls_get_ctx(sk);
+ struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx);
+ struct tls_rec *rec, *tmp;
++ int pending;
+
+ /* Wait for any pending async encryptions to complete */
+- smp_store_mb(ctx->async_notify, true);
+- if (atomic_read(&ctx->encrypt_pending))
++ spin_lock_bh(&ctx->encrypt_compl_lock);
++ ctx->async_notify = true;
++ pending = atomic_read(&ctx->encrypt_pending);
++ spin_unlock_bh(&ctx->encrypt_compl_lock);
++
++ if (pending)
+ crypto_wait_req(-EINPROGRESS, &ctx->async_wait);
+
+ tls_tx_records(sk, -1);
+diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
+index 279c87a2a523b..4d7b255067225 100644
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -4172,6 +4172,9 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
+ if (err)
+ return err;
+
++ if (key.idx < 0)
++ return -EINVAL;
++
+ if (info->attrs[NL80211_ATTR_MAC])
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
+index 3700266229f63..dcce888b8ef54 100644
+--- a/net/xdp/xsk.c
++++ b/net/xdp/xsk.c
+@@ -375,15 +375,30 @@ static int xsk_generic_xmit(struct sock *sk)
+ skb_shinfo(skb)->destructor_arg = (void *)(long)desc.addr;
+ skb->destructor = xsk_destruct_skb;
+
++ /* Hinder dev_direct_xmit from freeing the packet and
++ * therefore completing it in the destructor
++ */
++ refcount_inc(&skb->users);
+ err = dev_direct_xmit(skb, xs->queue_id);
++ if (err == NETDEV_TX_BUSY) {
++ /* Tell user-space to retry the send */
++ skb->destructor = sock_wfree;
++ /* Free skb without triggering the perf drop trace */
++ consume_skb(skb);
++ err = -EAGAIN;
++ goto out;
++ }
++
+ xskq_cons_release(xs->tx);
+ /* Ignore NET_XMIT_CN as packet might have been sent */
+- if (err == NET_XMIT_DROP || err == NETDEV_TX_BUSY) {
++ if (err == NET_XMIT_DROP) {
+ /* SKB completed but not sent */
++ kfree_skb(skb);
+ err = -EBUSY;
+ goto out;
+ }
+
++ consume_skb(skb);
+ sent_frame = true;
+ }
+
+diff --git a/net/xfrm/espintcp.c b/net/xfrm/espintcp.c
+index 827ccdf2db57f..1f08ebf7d80c5 100644
+--- a/net/xfrm/espintcp.c
++++ b/net/xfrm/espintcp.c
+@@ -29,8 +29,12 @@ static void handle_nonesp(struct espintcp_ctx *ctx, struct sk_buff *skb,
+
+ static void handle_esp(struct sk_buff *skb, struct sock *sk)
+ {
++ struct tcp_skb_cb *tcp_cb = (struct tcp_skb_cb *)skb->cb;
++
+ skb_reset_transport_header(skb);
+- memset(skb->cb, 0, sizeof(skb->cb));
++
++ /* restore IP CB, we need at least IP6CB->nhoff */
++ memmove(skb->cb, &tcp_cb->header, sizeof(tcp_cb->header));
+
+ rcu_read_lock();
+ skb->dev = dev_get_by_index_rcu(sock_net(sk), skb->skb_iif);
+diff --git a/net/xfrm/xfrm_interface.c b/net/xfrm/xfrm_interface.c
+index b615729812e5a..ade2eba863b39 100644
+--- a/net/xfrm/xfrm_interface.c
++++ b/net/xfrm/xfrm_interface.c
+@@ -292,7 +292,7 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
+ }
+
+ mtu = dst_mtu(dst);
+- if (!skb->ignore_df && skb->len > mtu) {
++ if (skb->len > mtu) {
+ skb_dst_update_pmtu_no_confirm(skb, mtu);
+
+ if (skb->protocol == htons(ETH_P_IPV6)) {
+diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
+index 8be2d926acc21..158510cd34ae8 100644
+--- a/net/xfrm/xfrm_state.c
++++ b/net/xfrm/xfrm_state.c
+@@ -1019,7 +1019,8 @@ static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x,
+ */
+ if (x->km.state == XFRM_STATE_VALID) {
+ if ((x->sel.family &&
+- !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
++ (x->sel.family != family ||
++ !xfrm_selector_match(&x->sel, fl, family))) ||
+ !security_xfrm_state_pol_flow_match(x, pol, fl))
+ return;
+
+@@ -1032,7 +1033,9 @@ static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x,
+ *acq_in_progress = 1;
+ } else if (x->km.state == XFRM_STATE_ERROR ||
+ x->km.state == XFRM_STATE_EXPIRED) {
+- if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
++ if ((!x->sel.family ||
++ (x->sel.family == family &&
++ xfrm_selector_match(&x->sel, fl, family))) &&
+ security_xfrm_state_pol_flow_match(x, pol, fl))
+ *error = -ESRCH;
+ }
+@@ -1072,7 +1075,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
+ tmpl->mode == x->props.mode &&
+ tmpl->id.proto == x->id.proto &&
+ (tmpl->id.spi == x->id.spi || !tmpl->id.spi))
+- xfrm_state_look_at(pol, x, fl, encap_family,
++ xfrm_state_look_at(pol, x, fl, family,
+ &best, &acquire_in_progress, &error);
+ }
+ if (best || acquire_in_progress)
+@@ -1089,7 +1092,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
+ tmpl->mode == x->props.mode &&
+ tmpl->id.proto == x->id.proto &&
+ (tmpl->id.spi == x->id.spi || !tmpl->id.spi))
+- xfrm_state_look_at(pol, x, fl, encap_family,
++ xfrm_state_look_at(pol, x, fl, family,
+ &best, &acquire_in_progress, &error);
+ }
+
+@@ -1441,6 +1444,30 @@ out:
+ EXPORT_SYMBOL(xfrm_state_add);
+
+ #ifdef CONFIG_XFRM_MIGRATE
++static inline int clone_security(struct xfrm_state *x, struct xfrm_sec_ctx *security)
++{
++ struct xfrm_user_sec_ctx *uctx;
++ int size = sizeof(*uctx) + security->ctx_len;
++ int err;
++
++ uctx = kmalloc(size, GFP_KERNEL);
++ if (!uctx)
++ return -ENOMEM;
++
++ uctx->exttype = XFRMA_SEC_CTX;
++ uctx->len = size;
++ uctx->ctx_doi = security->ctx_doi;
++ uctx->ctx_alg = security->ctx_alg;
++ uctx->ctx_len = security->ctx_len;
++ memcpy(uctx + 1, security->ctx_str, security->ctx_len);
++ err = security_xfrm_state_alloc(x, uctx);
++ kfree(uctx);
++ if (err)
++ return err;
++
++ return 0;
++}
++
+ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
+ struct xfrm_encap_tmpl *encap)
+ {
+@@ -1497,6 +1524,10 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
+ goto error;
+ }
+
++ if (orig->security)
++ if (clone_security(x, orig->security))
++ goto error;
++
+ if (orig->coaddr) {
+ x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),
+ GFP_KERNEL);
+@@ -1510,6 +1541,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
+ }
+
+ memcpy(&x->mark, &orig->mark, sizeof(x->mark));
++ memcpy(&x->props.smark, &orig->props.smark, sizeof(x->props.smark));
+
+ if (xfrm_init_state(x) < 0)
+ goto error;
+@@ -1521,7 +1553,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
+ x->tfcpad = orig->tfcpad;
+ x->replay_maxdiff = orig->replay_maxdiff;
+ x->replay_maxage = orig->replay_maxage;
+- x->curlft.add_time = orig->curlft.add_time;
++ memcpy(&x->curlft, &orig->curlft, sizeof(x->curlft));
+ x->km.state = orig->km.state;
+ x->km.seq = orig->km.seq;
+ x->replay = orig->replay;