summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--0000_README4
-rw-r--r--1013_linux-5.19.14.patch5315
2 files changed, 5319 insertions, 0 deletions
diff --git a/0000_README b/0000_README
index 56f7e0a3..df106d7b 100644
--- a/0000_README
+++ b/0000_README
@@ -95,6 +95,10 @@ Patch: 1012_linux-5.19.13.patch
From: http://www.kernel.org
Desc: Linux 5.19.13
+Patch: 1013_linux-5.19.14.patch
+From: http://www.kernel.org
+Desc: Linux 5.19.14
+
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/1013_linux-5.19.14.patch b/1013_linux-5.19.14.patch
new file mode 100644
index 00000000..40991ab7
--- /dev/null
+++ b/1013_linux-5.19.14.patch
@@ -0,0 +1,5315 @@
+diff --git a/Makefile b/Makefile
+index 2ecedf786e273..ff4a158671455 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ VERSION = 5
+ PATCHLEVEL = 19
+-SUBLEVEL = 13
++SUBLEVEL = 14
+ EXTRAVERSION =
+ NAME = Superb Owl
+
+diff --git a/arch/arm/boot/dts/am33xx-l4.dtsi b/arch/arm/boot/dts/am33xx-l4.dtsi
+index 7da42a5b959cf..7e50fe633d8a1 100644
+--- a/arch/arm/boot/dts/am33xx-l4.dtsi
++++ b/arch/arm/boot/dts/am33xx-l4.dtsi
+@@ -1502,8 +1502,7 @@
+ mmc1: mmc@0 {
+ compatible = "ti,am335-sdhci";
+ ti,needs-special-reset;
+- dmas = <&edma_xbar 24 0 0
+- &edma_xbar 25 0 0>;
++ dmas = <&edma 24 0>, <&edma 25 0>;
+ dma-names = "tx", "rx";
+ interrupts = <64>;
+ reg = <0x0 0x1000>;
+diff --git a/arch/arm/boot/dts/am5748.dtsi b/arch/arm/boot/dts/am5748.dtsi
+index c260aa1a85bdb..a1f029e9d1f3d 100644
+--- a/arch/arm/boot/dts/am5748.dtsi
++++ b/arch/arm/boot/dts/am5748.dtsi
+@@ -25,6 +25,10 @@
+ status = "disabled";
+ };
+
++&usb4_tm {
++ status = "disabled";
++};
++
+ &atl_tm {
+ status = "disabled";
+ };
+diff --git a/arch/arm/boot/dts/integratorap.dts b/arch/arm/boot/dts/integratorap.dts
+index 9b652cc27b141..c983435ed492e 100644
+--- a/arch/arm/boot/dts/integratorap.dts
++++ b/arch/arm/boot/dts/integratorap.dts
+@@ -160,6 +160,7 @@
+
+ pci: pciv3@62000000 {
+ compatible = "arm,integrator-ap-pci", "v3,v360epc-pci";
++ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi
+index 3293f76478df4..0e5a4fbb5eb19 100644
+--- a/arch/arm64/boot/dts/qcom/sm8350.dtsi
++++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi
+@@ -2128,7 +2128,7 @@
+
+ ufs_mem_phy: phy@1d87000 {
+ compatible = "qcom,sm8350-qmp-ufs-phy";
+- reg = <0 0x01d87000 0 0xe10>;
++ reg = <0 0x01d87000 0 0x1c4>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c
+index db2f3d1934481..33d50f38f2e06 100644
+--- a/arch/powerpc/mm/book3s64/radix_pgtable.c
++++ b/arch/powerpc/mm/book3s64/radix_pgtable.c
+@@ -937,15 +937,6 @@ pmd_t radix__pmdp_collapse_flush(struct vm_area_struct *vma, unsigned long addre
+ pmd = *pmdp;
+ pmd_clear(pmdp);
+
+- /*
+- * pmdp collapse_flush need to ensure that there are no parallel gup
+- * walk after this call. This is needed so that we can have stable
+- * page ref count when collapsing a page. We don't allow a collapse page
+- * if we have gup taken on the page. We can ensure that by sending IPI
+- * because gup walk happens with IRQ disabled.
+- */
+- serialize_against_pte_lookup(vma->vm_mm);
+-
+ radix__flush_tlb_collapsed_pmd(vma->vm_mm, address);
+
+ return pmd;
+diff --git a/arch/riscv/Kconfig.erratas b/arch/riscv/Kconfig.erratas
+index 457ac72c9b36d..e59a770b4432f 100644
+--- a/arch/riscv/Kconfig.erratas
++++ b/arch/riscv/Kconfig.erratas
+@@ -46,7 +46,7 @@ config ERRATA_THEAD
+
+ config ERRATA_THEAD_PBMT
+ bool "Apply T-Head memory type errata"
+- depends on ERRATA_THEAD && 64BIT
++ depends on ERRATA_THEAD && 64BIT && MMU
+ select RISCV_ALTERNATIVE_EARLY
+ default y
+ help
+diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h
+index 81a0211a372d3..a73bced40e241 100644
+--- a/arch/x86/include/asm/smp.h
++++ b/arch/x86/include/asm/smp.h
+@@ -21,16 +21,6 @@ DECLARE_PER_CPU_READ_MOSTLY(u16, cpu_llc_id);
+ DECLARE_PER_CPU_READ_MOSTLY(u16, cpu_l2c_id);
+ DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number);
+
+-static inline struct cpumask *cpu_llc_shared_mask(int cpu)
+-{
+- return per_cpu(cpu_llc_shared_map, cpu);
+-}
+-
+-static inline struct cpumask *cpu_l2c_shared_mask(int cpu)
+-{
+- return per_cpu(cpu_l2c_shared_map, cpu);
+-}
+-
+ DECLARE_EARLY_PER_CPU_READ_MOSTLY(u16, x86_cpu_to_apicid);
+ DECLARE_EARLY_PER_CPU_READ_MOSTLY(u32, x86_cpu_to_acpiid);
+ DECLARE_EARLY_PER_CPU_READ_MOSTLY(u16, x86_bios_cpu_apicid);
+@@ -172,6 +162,16 @@ extern int safe_smp_processor_id(void);
+ # define safe_smp_processor_id() smp_processor_id()
+ #endif
+
++static inline struct cpumask *cpu_llc_shared_mask(int cpu)
++{
++ return per_cpu(cpu_llc_shared_map, cpu);
++}
++
++static inline struct cpumask *cpu_l2c_shared_mask(int cpu)
++{
++ return per_cpu(cpu_l2c_shared_map, cpu);
++}
++
+ #else /* !CONFIG_SMP */
+ #define wbinvd_on_cpu(cpu) wbinvd()
+ static inline int wbinvd_on_all_cpus(void)
+@@ -179,6 +179,11 @@ static inline int wbinvd_on_all_cpus(void)
+ wbinvd();
+ return 0;
+ }
++
++static inline struct cpumask *cpu_llc_shared_mask(int cpu)
++{
++ return (struct cpumask *)cpumask_of(0);
++}
+ #endif /* CONFIG_SMP */
+
+ extern unsigned disabled_cpus;
+diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
+index 62f6b8b7c4a52..4f3204364caa5 100644
+--- a/arch/x86/kernel/alternative.c
++++ b/arch/x86/kernel/alternative.c
+@@ -1319,22 +1319,23 @@ struct bp_patching_desc {
+ atomic_t refs;
+ };
+
+-static struct bp_patching_desc *bp_desc;
++static struct bp_patching_desc bp_desc;
+
+ static __always_inline
+-struct bp_patching_desc *try_get_desc(struct bp_patching_desc **descp)
++struct bp_patching_desc *try_get_desc(void)
+ {
+- /* rcu_dereference */
+- struct bp_patching_desc *desc = __READ_ONCE(*descp);
++ struct bp_patching_desc *desc = &bp_desc;
+
+- if (!desc || !arch_atomic_inc_not_zero(&desc->refs))
++ if (!arch_atomic_inc_not_zero(&desc->refs))
+ return NULL;
+
+ return desc;
+ }
+
+-static __always_inline void put_desc(struct bp_patching_desc *desc)
++static __always_inline void put_desc(void)
+ {
++ struct bp_patching_desc *desc = &bp_desc;
++
+ smp_mb__before_atomic();
+ arch_atomic_dec(&desc->refs);
+ }
+@@ -1367,15 +1368,15 @@ noinstr int poke_int3_handler(struct pt_regs *regs)
+
+ /*
+ * Having observed our INT3 instruction, we now must observe
+- * bp_desc:
++ * bp_desc with non-zero refcount:
+ *
+- * bp_desc = desc INT3
++ * bp_desc.refs = 1 INT3
+ * WMB RMB
+- * write INT3 if (desc)
++ * write INT3 if (bp_desc.refs != 0)
+ */
+ smp_rmb();
+
+- desc = try_get_desc(&bp_desc);
++ desc = try_get_desc();
+ if (!desc)
+ return 0;
+
+@@ -1429,7 +1430,7 @@ noinstr int poke_int3_handler(struct pt_regs *regs)
+ ret = 1;
+
+ out_put:
+- put_desc(desc);
++ put_desc();
+ return ret;
+ }
+
+@@ -1460,18 +1461,20 @@ static int tp_vec_nr;
+ */
+ static void text_poke_bp_batch(struct text_poke_loc *tp, unsigned int nr_entries)
+ {
+- struct bp_patching_desc desc = {
+- .vec = tp,
+- .nr_entries = nr_entries,
+- .refs = ATOMIC_INIT(1),
+- };
+ unsigned char int3 = INT3_INSN_OPCODE;
+ unsigned int i;
+ int do_sync;
+
+ lockdep_assert_held(&text_mutex);
+
+- smp_store_release(&bp_desc, &desc); /* rcu_assign_pointer */
++ bp_desc.vec = tp;
++ bp_desc.nr_entries = nr_entries;
++
++ /*
++ * Corresponds to the implicit memory barrier in try_get_desc() to
++ * ensure reading a non-zero refcount provides up to date bp_desc data.
++ */
++ atomic_set_release(&bp_desc.refs, 1);
+
+ /*
+ * Corresponding read barrier in int3 notifier for making sure the
+@@ -1559,12 +1562,10 @@ static void text_poke_bp_batch(struct text_poke_loc *tp, unsigned int nr_entries
+ text_poke_sync();
+
+ /*
+- * Remove and synchronize_rcu(), except we have a very primitive
+- * refcount based completion.
++ * Remove and wait for refs to be zero.
+ */
+- WRITE_ONCE(bp_desc, NULL); /* RCU_INIT_POINTER */
+- if (!atomic_dec_and_test(&desc.refs))
+- atomic_cond_read_acquire(&desc.refs, !VAL);
++ if (!atomic_dec_and_test(&bp_desc.refs))
++ atomic_cond_read_acquire(&bp_desc.refs, !VAL);
+ }
+
+ static void text_poke_loc_init(struct text_poke_loc *tp, void *addr,
+diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c
+index a78652d43e61b..9fbc43b6b8b45 100644
+--- a/arch/x86/kernel/cpu/sgx/main.c
++++ b/arch/x86/kernel/cpu/sgx/main.c
+@@ -49,9 +49,13 @@ static LIST_HEAD(sgx_dirty_page_list);
+ * Reset post-kexec EPC pages to the uninitialized state. The pages are removed
+ * from the input list, and made available for the page allocator. SECS pages
+ * prepending their children in the input list are left intact.
++ *
++ * Return 0 when sanitization was successful or kthread was stopped, and the
++ * number of unsanitized pages otherwise.
+ */
+-static void __sgx_sanitize_pages(struct list_head *dirty_page_list)
++static unsigned long __sgx_sanitize_pages(struct list_head *dirty_page_list)
+ {
++ unsigned long left_dirty = 0;
+ struct sgx_epc_page *page;
+ LIST_HEAD(dirty);
+ int ret;
+@@ -59,7 +63,7 @@ static void __sgx_sanitize_pages(struct list_head *dirty_page_list)
+ /* dirty_page_list is thread-local, no need for a lock: */
+ while (!list_empty(dirty_page_list)) {
+ if (kthread_should_stop())
+- return;
++ return 0;
+
+ page = list_first_entry(dirty_page_list, struct sgx_epc_page, list);
+
+@@ -92,12 +96,14 @@ static void __sgx_sanitize_pages(struct list_head *dirty_page_list)
+ } else {
+ /* The page is not yet clean - move to the dirty list. */
+ list_move_tail(&page->list, &dirty);
++ left_dirty++;
+ }
+
+ cond_resched();
+ }
+
+ list_splice(&dirty, dirty_page_list);
++ return left_dirty;
+ }
+
+ static bool sgx_reclaimer_age(struct sgx_epc_page *epc_page)
+@@ -440,10 +446,7 @@ static int ksgxd(void *p)
+ * required for SECS pages, whose child pages blocked EREMOVE.
+ */
+ __sgx_sanitize_pages(&sgx_dirty_page_list);
+- __sgx_sanitize_pages(&sgx_dirty_page_list);
+-
+- /* sanity check: */
+- WARN_ON(!list_empty(&sgx_dirty_page_list));
++ WARN_ON(__sgx_sanitize_pages(&sgx_dirty_page_list));
+
+ while (!kthread_should_stop()) {
+ if (try_to_freeze())
+diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
+index 3ab498165639f..cb14441cee37d 100644
+--- a/arch/x86/kvm/cpuid.c
++++ b/arch/x86/kvm/cpuid.c
+@@ -870,8 +870,6 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
+ entry->edx = 0;
+ }
+ break;
+- case 9:
+- break;
+ case 0xa: { /* Architectural Performance Monitoring */
+ struct x86_pmu_capability cap;
+ union cpuid10_eax eax;
+diff --git a/arch/x86/lib/usercopy.c b/arch/x86/lib/usercopy.c
+index ad0139d254014..f1bb186171562 100644
+--- a/arch/x86/lib/usercopy.c
++++ b/arch/x86/lib/usercopy.c
+@@ -44,7 +44,7 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
+ * called from other contexts.
+ */
+ pagefault_disable();
+- ret = __copy_from_user_inatomic(to, from, n);
++ ret = raw_copy_from_user(to, from, n);
+ pagefault_enable();
+
+ return ret;
+diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
+index 9601fa92950a0..6211d5bb76371 100644
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -3988,6 +3988,10 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
+ { "PIONEER DVD-RW DVR-212D", NULL, ATA_HORKAGE_NOSETXFER },
+ { "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER },
+
++ /* These specific Pioneer models have LPM issues */
++ { "PIONEER BD-RW BDR-207M", NULL, ATA_HORKAGE_NOLPM },
++ { "PIONEER BD-RW BDR-205", NULL, ATA_HORKAGE_NOLPM },
++
+ /* Crucial BX100 SSD 500GB has broken LPM support */
+ { "CT500BX100SSD1", NULL, ATA_HORKAGE_NOLPM },
+
+diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
+index 59d6d5faf7396..dcd639e58ff06 100644
+--- a/drivers/block/virtio_blk.c
++++ b/drivers/block/virtio_blk.c
+@@ -322,14 +322,14 @@ static blk_status_t virtblk_prep_rq(struct blk_mq_hw_ctx *hctx,
+ if (unlikely(status))
+ return status;
+
+- blk_mq_start_request(req);
+-
+ vbr->sg_table.nents = virtblk_map_data(hctx, req, vbr);
+ if (unlikely(vbr->sg_table.nents < 0)) {
+ virtblk_cleanup_cmd(req);
+ return BLK_STS_RESOURCE;
+ }
+
++ blk_mq_start_request(req);
++
+ return BLK_STS_OK;
+ }
+
+@@ -391,8 +391,7 @@ static bool virtblk_prep_rq_batch(struct request *req)
+ }
+
+ static bool virtblk_add_req_batch(struct virtio_blk_vq *vq,
+- struct request **rqlist,
+- struct request **requeue_list)
++ struct request **rqlist)
+ {
+ unsigned long flags;
+ int err;
+@@ -408,7 +407,7 @@ static bool virtblk_add_req_batch(struct virtio_blk_vq *vq,
+ if (err) {
+ virtblk_unmap_data(req, vbr);
+ virtblk_cleanup_cmd(req);
+- rq_list_add(requeue_list, req);
++ blk_mq_requeue_request(req, true);
+ }
+ }
+
+@@ -436,7 +435,7 @@ static void virtio_queue_rqs(struct request **rqlist)
+
+ if (!next || req->mq_hctx != next->mq_hctx) {
+ req->rq_next = NULL;
+- kick = virtblk_add_req_batch(vq, rqlist, &requeue_list);
++ kick = virtblk_add_req_batch(vq, rqlist);
+ if (kick)
+ virtqueue_notify(vq->vq);
+
+diff --git a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c
+index 33da30f99c79b..d39c44b61c523 100644
+--- a/drivers/clk/bcm/clk-iproc-pll.c
++++ b/drivers/clk/bcm/clk-iproc-pll.c
+@@ -736,6 +736,7 @@ void iproc_pll_clk_setup(struct device_node *node,
+ const char *parent_name;
+ struct iproc_clk *iclk_array;
+ struct clk_hw_onecell_data *clk_data;
++ const char *clk_name;
+
+ if (WARN_ON(!pll_ctrl) || WARN_ON(!clk_ctrl))
+ return;
+@@ -783,7 +784,12 @@ void iproc_pll_clk_setup(struct device_node *node,
+ iclk = &iclk_array[0];
+ iclk->pll = pll;
+
+- init.name = node->name;
++ ret = of_property_read_string_index(node, "clock-output-names",
++ 0, &clk_name);
++ if (WARN_ON(ret))
++ goto err_pll_register;
++
++ init.name = clk_name;
+ init.ops = &iproc_pll_ops;
+ init.flags = 0;
+ parent_name = of_clk_get_parent_name(node, 0);
+@@ -803,13 +809,11 @@ void iproc_pll_clk_setup(struct device_node *node,
+ goto err_pll_register;
+
+ clk_data->hws[0] = &iclk->hw;
++ parent_name = clk_name;
+
+ /* now initialize and register all leaf clocks */
+ for (i = 1; i < num_clks; i++) {
+- const char *clk_name;
+-
+ memset(&init, 0, sizeof(init));
+- parent_name = node->name;
+
+ ret = of_property_read_string_index(node, "clock-output-names",
+ i, &clk_name);
+diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c
+index fc1bd23d45834..598f3cf4eba49 100644
+--- a/drivers/clk/imx/clk-imx6sx.c
++++ b/drivers/clk/imx/clk-imx6sx.c
+@@ -280,13 +280,13 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
+ hws[IMX6SX_CLK_SSI3_SEL] = imx_clk_hw_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+ hws[IMX6SX_CLK_SSI2_SEL] = imx_clk_hw_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+ hws[IMX6SX_CLK_SSI1_SEL] = imx_clk_hw_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+- hws[IMX6SX_CLK_QSPI1_SEL] = imx_clk_hw_mux_flags("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels), CLK_SET_RATE_PARENT);
++ hws[IMX6SX_CLK_QSPI1_SEL] = imx_clk_hw_mux("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels));
+ hws[IMX6SX_CLK_PERCLK_SEL] = imx_clk_hw_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels));
+ hws[IMX6SX_CLK_VID_SEL] = imx_clk_hw_mux("vid_sel", base + 0x20, 21, 3, vid_sels, ARRAY_SIZE(vid_sels));
+ hws[IMX6SX_CLK_ESAI_SEL] = imx_clk_hw_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels));
+ hws[IMX6SX_CLK_CAN_SEL] = imx_clk_hw_mux("can_sel", base + 0x20, 8, 2, can_sels, ARRAY_SIZE(can_sels));
+ hws[IMX6SX_CLK_UART_SEL] = imx_clk_hw_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
+- hws[IMX6SX_CLK_QSPI2_SEL] = imx_clk_hw_mux_flags("qspi2_sel", base + 0x2c, 15, 3, qspi2_sels, ARRAY_SIZE(qspi2_sels), CLK_SET_RATE_PARENT);
++ hws[IMX6SX_CLK_QSPI2_SEL] = imx_clk_hw_mux("qspi2_sel", base + 0x2c, 15, 3, qspi2_sels, ARRAY_SIZE(qspi2_sels));
+ hws[IMX6SX_CLK_SPDIF_SEL] = imx_clk_hw_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels));
+ hws[IMX6SX_CLK_AUDIO_SEL] = imx_clk_hw_mux("audio_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels));
+ hws[IMX6SX_CLK_ENET_PRE_SEL] = imx_clk_hw_mux("enet_pre_sel", base + 0x34, 15, 3, enet_pre_sels, ARRAY_SIZE(enet_pre_sels));
+diff --git a/drivers/clk/imx/clk-imx93.c b/drivers/clk/imx/clk-imx93.c
+index f5c9fa40491c5..dcc41d178238e 100644
+--- a/drivers/clk/imx/clk-imx93.c
++++ b/drivers/clk/imx/clk-imx93.c
+@@ -332,7 +332,7 @@ static struct platform_driver imx93_clk_driver = {
+ .driver = {
+ .name = "imx93-ccm",
+ .suppress_bind_attrs = true,
+- .of_match_table = of_match_ptr(imx93_clk_of_match),
++ .of_match_table = imx93_clk_of_match,
+ },
+ };
+ module_platform_driver(imx93_clk_driver);
+diff --git a/drivers/clk/ingenic/tcu.c b/drivers/clk/ingenic/tcu.c
+index 201bf6e6b6e0f..d5544cbc5c484 100644
+--- a/drivers/clk/ingenic/tcu.c
++++ b/drivers/clk/ingenic/tcu.c
+@@ -101,15 +101,11 @@ static bool ingenic_tcu_enable_regs(struct clk_hw *hw)
+ bool enabled = false;
+
+ /*
+- * If the SoC has no global TCU clock, we must ungate the channel's
+- * clock to be able to access its registers.
+- * If we have a TCU clock, it will be enabled automatically as it has
+- * been attached to the regmap.
++ * According to the programming manual, a timer channel's registers can
++ * only be accessed when the channel's stop bit is clear.
+ */
+- if (!tcu->clk) {
+- enabled = !!ingenic_tcu_is_enabled(hw);
+- regmap_write(tcu->map, TCU_REG_TSCR, BIT(info->gate_bit));
+- }
++ enabled = !!ingenic_tcu_is_enabled(hw);
++ regmap_write(tcu->map, TCU_REG_TSCR, BIT(info->gate_bit));
+
+ return enabled;
+ }
+@@ -120,8 +116,7 @@ static void ingenic_tcu_disable_regs(struct clk_hw *hw)
+ const struct ingenic_tcu_clk_info *info = tcu_clk->info;
+ struct ingenic_tcu *tcu = tcu_clk->tcu;
+
+- if (!tcu->clk)
+- regmap_write(tcu->map, TCU_REG_TSSR, BIT(info->gate_bit));
++ regmap_write(tcu->map, TCU_REG_TSSR, BIT(info->gate_bit));
+ }
+
+ static u8 ingenic_tcu_get_parent(struct clk_hw *hw)
+diff --git a/drivers/clk/microchip/clk-mpfs.c b/drivers/clk/microchip/clk-mpfs.c
+index 070c3b8965590..b6b89413e0904 100644
+--- a/drivers/clk/microchip/clk-mpfs.c
++++ b/drivers/clk/microchip/clk-mpfs.c
+@@ -239,6 +239,11 @@ static const struct clk_ops mpfs_clk_cfg_ops = {
+ .hw.init = CLK_HW_INIT(_name, _parent, &mpfs_clk_cfg_ops, 0), \
+ }
+
++#define CLK_CPU_OFFSET 0u
++#define CLK_AXI_OFFSET 1u
++#define CLK_AHB_OFFSET 2u
++#define CLK_RTCREF_OFFSET 3u
++
+ static struct mpfs_cfg_hw_clock mpfs_cfg_clks[] = {
+ CLK_CFG(CLK_CPU, "clk_cpu", "clk_msspll", 0, 2, mpfs_div_cpu_axi_table, 0,
+ REG_CLOCK_CONFIG_CR),
+@@ -362,7 +367,7 @@ static const struct clk_ops mpfs_periph_clk_ops = {
+ _flags), \
+ }
+
+-#define PARENT_CLK(PARENT) (&mpfs_cfg_clks[CLK_##PARENT].hw)
++#define PARENT_CLK(PARENT) (&mpfs_cfg_clks[CLK_##PARENT##_OFFSET].hw)
+
+ /*
+ * Critical clocks:
+@@ -370,6 +375,8 @@ static const struct clk_ops mpfs_periph_clk_ops = {
+ * trap handler
+ * - CLK_MMUART0: reserved by the hss
+ * - CLK_DDRC: provides clock to the ddr subsystem
++ * - CLK_RTC: the onboard RTC's AHB bus clock must be kept running as the rtc will stop
++ * if the AHB interface clock is disabled
+ * - CLK_FICx: these provide the processor side clocks to the "FIC" (Fabric InterConnect)
+ * clock domain crossers which provide the interface to the FPGA fabric. Disabling them
+ * causes the FPGA fabric to go into reset.
+@@ -394,7 +401,7 @@ static struct mpfs_periph_hw_clock mpfs_periph_clks[] = {
+ CLK_PERIPH(CLK_CAN0, "clk_periph_can0", PARENT_CLK(AHB), 14, 0),
+ CLK_PERIPH(CLK_CAN1, "clk_periph_can1", PARENT_CLK(AHB), 15, 0),
+ CLK_PERIPH(CLK_USB, "clk_periph_usb", PARENT_CLK(AHB), 16, 0),
+- CLK_PERIPH(CLK_RTC, "clk_periph_rtc", PARENT_CLK(AHB), 18, 0),
++ CLK_PERIPH(CLK_RTC, "clk_periph_rtc", PARENT_CLK(AHB), 18, CLK_IS_CRITICAL),
+ CLK_PERIPH(CLK_QSPI, "clk_periph_qspi", PARENT_CLK(AHB), 19, 0),
+ CLK_PERIPH(CLK_GPIO0, "clk_periph_gpio0", PARENT_CLK(AHB), 20, 0),
+ CLK_PERIPH(CLK_GPIO1, "clk_periph_gpio1", PARENT_CLK(AHB), 21, 0),
+diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c
+index a17e51d65aca8..4407203e0c9b3 100644
+--- a/drivers/counter/104-quad-8.c
++++ b/drivers/counter/104-quad-8.c
+@@ -33,6 +33,36 @@ MODULE_PARM_DESC(irq, "ACCES 104-QUAD-8 interrupt line numbers");
+
+ #define QUAD8_NUM_COUNTERS 8
+
++/**
++ * struct channel_reg - channel register structure
++ * @data: Count data
++ * @control: Channel flags and control
++ */
++struct channel_reg {
++ u8 data;
++ u8 control;
++};
++
++/**
++ * struct quad8_reg - device register structure
++ * @channel: quadrature counter data and control
++ * @interrupt_status: channel interrupt status
++ * @channel_oper: enable/reset counters and interrupt functions
++ * @index_interrupt: enable channel interrupts
++ * @reserved: reserved for Factory Use
++ * @index_input_levels: index signal logical input level
++ * @cable_status: differential encoder cable status
++ */
++struct quad8_reg {
++ struct channel_reg channel[QUAD8_NUM_COUNTERS];
++ u8 interrupt_status;
++ u8 channel_oper;
++ u8 index_interrupt;
++ u8 reserved[3];
++ u8 index_input_levels;
++ u8 cable_status;
++};
++
+ /**
+ * struct quad8 - device private data structure
+ * @lock: lock to prevent clobbering device states during R/W ops
+@@ -48,7 +78,7 @@ MODULE_PARM_DESC(irq, "ACCES 104-QUAD-8 interrupt line numbers");
+ * @synchronous_mode: array of index function synchronous mode configurations
+ * @index_polarity: array of index function polarity configurations
+ * @cable_fault_enable: differential encoder cable status enable configurations
+- * @base: base port address of the device
++ * @reg: I/O address offset for the device registers
+ */
+ struct quad8 {
+ spinlock_t lock;
+@@ -63,14 +93,9 @@ struct quad8 {
+ unsigned int synchronous_mode[QUAD8_NUM_COUNTERS];
+ unsigned int index_polarity[QUAD8_NUM_COUNTERS];
+ unsigned int cable_fault_enable;
+- unsigned int base;
++ struct quad8_reg __iomem *reg;
+ };
+
+-#define QUAD8_REG_INTERRUPT_STATUS 0x10
+-#define QUAD8_REG_CHAN_OP 0x11
+-#define QUAD8_REG_INDEX_INTERRUPT 0x12
+-#define QUAD8_REG_INDEX_INPUT_LEVELS 0x16
+-#define QUAD8_DIFF_ENCODER_CABLE_STATUS 0x17
+ /* Borrow Toggle flip-flop */
+ #define QUAD8_FLAG_BT BIT(0)
+ /* Carry Toggle flip-flop */
+@@ -118,8 +143,7 @@ static int quad8_signal_read(struct counter_device *counter,
+ if (signal->id < 16)
+ return -EINVAL;
+
+- state = inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS)
+- & BIT(signal->id - 16);
++ state = ioread8(&priv->reg->index_input_levels) & BIT(signal->id - 16);
+
+ *level = (state) ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
+
+@@ -130,14 +154,14 @@ static int quad8_count_read(struct counter_device *counter,
+ struct counter_count *count, u64 *val)
+ {
+ struct quad8 *const priv = counter_priv(counter);
+- const int base_offset = priv->base + 2 * count->id;
++ struct channel_reg __iomem *const chan = priv->reg->channel + count->id;
+ unsigned int flags;
+ unsigned int borrow;
+ unsigned int carry;
+ unsigned long irqflags;
+ int i;
+
+- flags = inb(base_offset + 1);
++ flags = ioread8(&chan->control);
+ borrow = flags & QUAD8_FLAG_BT;
+ carry = !!(flags & QUAD8_FLAG_CT);
+
+@@ -147,11 +171,11 @@ static int quad8_count_read(struct counter_device *counter,
+ spin_lock_irqsave(&priv->lock, irqflags);
+
+ /* Reset Byte Pointer; transfer Counter to Output Latch */
+- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT,
+- base_offset + 1);
++ iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT,
++ &chan->control);
+
+ for (i = 0; i < 3; i++)
+- *val |= (unsigned long)inb(base_offset) << (8 * i);
++ *val |= (unsigned long)ioread8(&chan->data) << (8 * i);
+
+ spin_unlock_irqrestore(&priv->lock, irqflags);
+
+@@ -162,7 +186,7 @@ static int quad8_count_write(struct counter_device *counter,
+ struct counter_count *count, u64 val)
+ {
+ struct quad8 *const priv = counter_priv(counter);
+- const int base_offset = priv->base + 2 * count->id;
++ struct channel_reg __iomem *const chan = priv->reg->channel + count->id;
+ unsigned long irqflags;
+ int i;
+
+@@ -173,27 +197,27 @@ static int quad8_count_write(struct counter_device *counter,
+ spin_lock_irqsave(&priv->lock, irqflags);
+
+ /* Reset Byte Pointer */
+- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
++ iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
+
+ /* Counter can only be set via Preset Register */
+ for (i = 0; i < 3; i++)
+- outb(val >> (8 * i), base_offset);
++ iowrite8(val >> (8 * i), &chan->data);
+
+ /* Transfer Preset Register to Counter */
+- outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1);
++ iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, &chan->control);
+
+ /* Reset Byte Pointer */
+- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
++ iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
+
+ /* Set Preset Register back to original value */
+ val = priv->preset[count->id];
+ for (i = 0; i < 3; i++)
+- outb(val >> (8 * i), base_offset);
++ iowrite8(val >> (8 * i), &chan->data);
+
+ /* Reset Borrow, Carry, Compare, and Sign flags */
+- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1);
++ iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, &chan->control);
+ /* Reset Error flag */
+- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1);
++ iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, &chan->control);
+
+ spin_unlock_irqrestore(&priv->lock, irqflags);
+
+@@ -246,7 +270,7 @@ static int quad8_function_write(struct counter_device *counter,
+ unsigned int *const quadrature_mode = priv->quadrature_mode + id;
+ unsigned int *const scale = priv->quadrature_scale + id;
+ unsigned int *const synchronous_mode = priv->synchronous_mode + id;
+- const int base_offset = priv->base + 2 * id + 1;
++ u8 __iomem *const control = &priv->reg->channel[id].control;
+ unsigned long irqflags;
+ unsigned int mode_cfg;
+ unsigned int idr_cfg;
+@@ -266,7 +290,7 @@ static int quad8_function_write(struct counter_device *counter,
+ if (*synchronous_mode) {
+ *synchronous_mode = 0;
+ /* Disable synchronous function mode */
+- outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
++ iowrite8(QUAD8_CTR_IDR | idr_cfg, control);
+ }
+ } else {
+ *quadrature_mode = 1;
+@@ -292,7 +316,7 @@ static int quad8_function_write(struct counter_device *counter,
+ }
+
+ /* Load mode configuration to Counter Mode Register */
+- outb(QUAD8_CTR_CMR | mode_cfg, base_offset);
++ iowrite8(QUAD8_CTR_CMR | mode_cfg, control);
+
+ spin_unlock_irqrestore(&priv->lock, irqflags);
+
+@@ -305,10 +329,10 @@ static int quad8_direction_read(struct counter_device *counter,
+ {
+ const struct quad8 *const priv = counter_priv(counter);
+ unsigned int ud_flag;
+- const unsigned int flag_addr = priv->base + 2 * count->id + 1;
++ u8 __iomem *const flag_addr = &priv->reg->channel[count->id].control;
+
+ /* U/D flag: nonzero = up, zero = down */
+- ud_flag = inb(flag_addr) & QUAD8_FLAG_UD;
++ ud_flag = ioread8(flag_addr) & QUAD8_FLAG_UD;
+
+ *direction = (ud_flag) ? COUNTER_COUNT_DIRECTION_FORWARD :
+ COUNTER_COUNT_DIRECTION_BACKWARD;
+@@ -402,7 +426,6 @@ static int quad8_events_configure(struct counter_device *counter)
+ struct counter_event_node *event_node;
+ unsigned int next_irq_trigger;
+ unsigned long ior_cfg;
+- unsigned long base_offset;
+
+ spin_lock_irqsave(&priv->lock, irqflags);
+
+@@ -426,6 +449,9 @@ static int quad8_events_configure(struct counter_device *counter)
+ return -EINVAL;
+ }
+
++ /* Enable IRQ line */
++ irq_enabled |= BIT(event_node->channel);
++
+ /* Skip configuration if it is the same as previously set */
+ if (priv->irq_trigger[event_node->channel] == next_irq_trigger)
+ continue;
+@@ -437,14 +463,11 @@ static int quad8_events_configure(struct counter_device *counter)
+ ior_cfg = priv->ab_enable[event_node->channel] |
+ priv->preset_enable[event_node->channel] << 1 |
+ priv->irq_trigger[event_node->channel] << 3;
+- base_offset = priv->base + 2 * event_node->channel + 1;
+- outb(QUAD8_CTR_IOR | ior_cfg, base_offset);
+-
+- /* Enable IRQ line */
+- irq_enabled |= BIT(event_node->channel);
++ iowrite8(QUAD8_CTR_IOR | ior_cfg,
++ &priv->reg->channel[event_node->channel].control);
+ }
+
+- outb(irq_enabled, priv->base + QUAD8_REG_INDEX_INTERRUPT);
++ iowrite8(irq_enabled, &priv->reg->index_interrupt);
+
+ spin_unlock_irqrestore(&priv->lock, irqflags);
+
+@@ -508,7 +531,7 @@ static int quad8_index_polarity_set(struct counter_device *counter,
+ {
+ struct quad8 *const priv = counter_priv(counter);
+ const size_t channel_id = signal->id - 16;
+- const int base_offset = priv->base + 2 * channel_id + 1;
++ u8 __iomem *const control = &priv->reg->channel[channel_id].control;
+ unsigned long irqflags;
+ unsigned int idr_cfg = index_polarity << 1;
+
+@@ -519,7 +542,7 @@ static int quad8_index_polarity_set(struct counter_device *counter,
+ priv->index_polarity[channel_id] = index_polarity;
+
+ /* Load Index Control configuration to Index Control Register */
+- outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
++ iowrite8(QUAD8_CTR_IDR | idr_cfg, control);
+
+ spin_unlock_irqrestore(&priv->lock, irqflags);
+
+@@ -549,7 +572,7 @@ static int quad8_synchronous_mode_set(struct counter_device *counter,
+ {
+ struct quad8 *const priv = counter_priv(counter);
+ const size_t channel_id = signal->id - 16;
+- const int base_offset = priv->base + 2 * channel_id + 1;
++ u8 __iomem *const control = &priv->reg->channel[channel_id].control;
+ unsigned long irqflags;
+ unsigned int idr_cfg = synchronous_mode;
+
+@@ -566,7 +589,7 @@ static int quad8_synchronous_mode_set(struct counter_device *counter,
+ priv->synchronous_mode[channel_id] = synchronous_mode;
+
+ /* Load Index Control configuration to Index Control Register */
+- outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
++ iowrite8(QUAD8_CTR_IDR | idr_cfg, control);
+
+ spin_unlock_irqrestore(&priv->lock, irqflags);
+
+@@ -614,7 +637,7 @@ static int quad8_count_mode_write(struct counter_device *counter,
+ struct quad8 *const priv = counter_priv(counter);
+ unsigned int count_mode;
+ unsigned int mode_cfg;
+- const int base_offset = priv->base + 2 * count->id + 1;
++ u8 __iomem *const control = &priv->reg->channel[count->id].control;
+ unsigned long irqflags;
+
+ /* Map Generic Counter count mode to 104-QUAD-8 count mode */
+@@ -648,7 +671,7 @@ static int quad8_count_mode_write(struct counter_device *counter,
+ mode_cfg |= (priv->quadrature_scale[count->id] + 1) << 3;
+
+ /* Load mode configuration to Counter Mode Register */
+- outb(QUAD8_CTR_CMR | mode_cfg, base_offset);
++ iowrite8(QUAD8_CTR_CMR | mode_cfg, control);
+
+ spin_unlock_irqrestore(&priv->lock, irqflags);
+
+@@ -669,7 +692,7 @@ static int quad8_count_enable_write(struct counter_device *counter,
+ struct counter_count *count, u8 enable)
+ {
+ struct quad8 *const priv = counter_priv(counter);
+- const int base_offset = priv->base + 2 * count->id;
++ u8 __iomem *const control = &priv->reg->channel[count->id].control;
+ unsigned long irqflags;
+ unsigned int ior_cfg;
+
+@@ -681,7 +704,7 @@ static int quad8_count_enable_write(struct counter_device *counter,
+ priv->irq_trigger[count->id] << 3;
+
+ /* Load I/O control configuration */
+- outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1);
++ iowrite8(QUAD8_CTR_IOR | ior_cfg, control);
+
+ spin_unlock_irqrestore(&priv->lock, irqflags);
+
+@@ -697,9 +720,9 @@ static int quad8_error_noise_get(struct counter_device *counter,
+ struct counter_count *count, u32 *noise_error)
+ {
+ const struct quad8 *const priv = counter_priv(counter);
+- const int base_offset = priv->base + 2 * count->id + 1;
++ u8 __iomem *const flag_addr = &priv->reg->channel[count->id].control;
+
+- *noise_error = !!(inb(base_offset) & QUAD8_FLAG_E);
++ *noise_error = !!(ioread8(flag_addr) & QUAD8_FLAG_E);
+
+ return 0;
+ }
+@@ -717,17 +740,17 @@ static int quad8_count_preset_read(struct counter_device *counter,
+ static void quad8_preset_register_set(struct quad8 *const priv, const int id,
+ const unsigned int preset)
+ {
+- const unsigned int base_offset = priv->base + 2 * id;
++ struct channel_reg __iomem *const chan = priv->reg->channel + id;
+ int i;
+
+ priv->preset[id] = preset;
+
+ /* Reset Byte Pointer */
+- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
++ iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
+
+ /* Set Preset Register */
+ for (i = 0; i < 3; i++)
+- outb(preset >> (8 * i), base_offset);
++ iowrite8(preset >> (8 * i), &chan->data);
+ }
+
+ static int quad8_count_preset_write(struct counter_device *counter,
+@@ -816,7 +839,7 @@ static int quad8_count_preset_enable_write(struct counter_device *counter,
+ u8 preset_enable)
+ {
+ struct quad8 *const priv = counter_priv(counter);
+- const int base_offset = priv->base + 2 * count->id + 1;
++ u8 __iomem *const control = &priv->reg->channel[count->id].control;
+ unsigned long irqflags;
+ unsigned int ior_cfg;
+
+@@ -831,7 +854,7 @@ static int quad8_count_preset_enable_write(struct counter_device *counter,
+ priv->irq_trigger[count->id] << 3;
+
+ /* Load I/O control configuration to Input / Output Control Register */
+- outb(QUAD8_CTR_IOR | ior_cfg, base_offset);
++ iowrite8(QUAD8_CTR_IOR | ior_cfg, control);
+
+ spin_unlock_irqrestore(&priv->lock, irqflags);
+
+@@ -858,7 +881,7 @@ static int quad8_signal_cable_fault_read(struct counter_device *counter,
+ }
+
+ /* Logic 0 = cable fault */
+- status = inb(priv->base + QUAD8_DIFF_ENCODER_CABLE_STATUS);
++ status = ioread8(&priv->reg->cable_status);
+
+ spin_unlock_irqrestore(&priv->lock, irqflags);
+
+@@ -899,7 +922,7 @@ static int quad8_signal_cable_fault_enable_write(struct counter_device *counter,
+ /* Enable is active low in Differential Encoder Cable Status register */
+ cable_fault_enable = ~priv->cable_fault_enable;
+
+- outb(cable_fault_enable, priv->base + QUAD8_DIFF_ENCODER_CABLE_STATUS);
++ iowrite8(cable_fault_enable, &priv->reg->cable_status);
+
+ spin_unlock_irqrestore(&priv->lock, irqflags);
+
+@@ -923,7 +946,7 @@ static int quad8_signal_fck_prescaler_write(struct counter_device *counter,
+ {
+ struct quad8 *const priv = counter_priv(counter);
+ const size_t channel_id = signal->id / 2;
+- const int base_offset = priv->base + 2 * channel_id;
++ struct channel_reg __iomem *const chan = priv->reg->channel + channel_id;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&priv->lock, irqflags);
+@@ -931,12 +954,12 @@ static int quad8_signal_fck_prescaler_write(struct counter_device *counter,
+ priv->fck_prescaler[channel_id] = prescaler;
+
+ /* Reset Byte Pointer */
+- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
++ iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
+
+ /* Set filter clock factor */
+- outb(prescaler, base_offset);
+- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC,
+- base_offset + 1);
++ iowrite8(prescaler, &chan->data);
++ iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC,
++ &chan->control);
+
+ spin_unlock_irqrestore(&priv->lock, irqflags);
+
+@@ -1084,12 +1107,11 @@ static irqreturn_t quad8_irq_handler(int irq, void *private)
+ {
+ struct counter_device *counter = private;
+ struct quad8 *const priv = counter_priv(counter);
+- const unsigned long base = priv->base;
+ unsigned long irq_status;
+ unsigned long channel;
+ u8 event;
+
+- irq_status = inb(base + QUAD8_REG_INTERRUPT_STATUS);
++ irq_status = ioread8(&priv->reg->interrupt_status);
+ if (!irq_status)
+ return IRQ_NONE;
+
+@@ -1118,17 +1140,43 @@ static irqreturn_t quad8_irq_handler(int irq, void *private)
+ }
+
+ /* Clear pending interrupts on device */
+- outb(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, base + QUAD8_REG_CHAN_OP);
++ iowrite8(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, &priv->reg->channel_oper);
+
+ return IRQ_HANDLED;
+ }
+
++static void quad8_init_counter(struct channel_reg __iomem *const chan)
++{
++ unsigned long i;
++
++ /* Reset Byte Pointer */
++ iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
++ /* Reset filter clock factor */
++ iowrite8(0, &chan->data);
++ iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC,
++ &chan->control);
++ /* Reset Byte Pointer */
++ iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
++ /* Reset Preset Register */
++ for (i = 0; i < 3; i++)
++ iowrite8(0x00, &chan->data);
++ /* Reset Borrow, Carry, Compare, and Sign flags */
++ iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, &chan->control);
++ /* Reset Error flag */
++ iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, &chan->control);
++ /* Binary encoding; Normal count; non-quadrature mode */
++ iowrite8(QUAD8_CTR_CMR, &chan->control);
++ /* Disable A and B inputs; preset on index; FLG1 as Carry */
++ iowrite8(QUAD8_CTR_IOR, &chan->control);
++ /* Disable index function; negative index polarity */
++ iowrite8(QUAD8_CTR_IDR, &chan->control);
++}
++
+ static int quad8_probe(struct device *dev, unsigned int id)
+ {
+ struct counter_device *counter;
+ struct quad8 *priv;
+- int i, j;
+- unsigned int base_offset;
++ unsigned long i;
+ int err;
+
+ if (!devm_request_region(dev, base[id], QUAD8_EXTENT, dev_name(dev))) {
+@@ -1142,6 +1190,10 @@ static int quad8_probe(struct device *dev, unsigned int id)
+ return -ENOMEM;
+ priv = counter_priv(counter);
+
++ priv->reg = devm_ioport_map(dev, base[id], QUAD8_EXTENT);
++ if (!priv->reg)
++ return -ENOMEM;
++
+ /* Initialize Counter device and driver data */
+ counter->name = dev_name(dev);
+ counter->parent = dev;
+@@ -1150,43 +1202,20 @@ static int quad8_probe(struct device *dev, unsigned int id)
+ counter->num_counts = ARRAY_SIZE(quad8_counts);
+ counter->signals = quad8_signals;
+ counter->num_signals = ARRAY_SIZE(quad8_signals);
+- priv->base = base[id];
+
+ spin_lock_init(&priv->lock);
+
+ /* Reset Index/Interrupt Register */
+- outb(0x00, base[id] + QUAD8_REG_INDEX_INTERRUPT);
++ iowrite8(0x00, &priv->reg->index_interrupt);
+ /* Reset all counters and disable interrupt function */
+- outb(QUAD8_CHAN_OP_RESET_COUNTERS, base[id] + QUAD8_REG_CHAN_OP);
++ iowrite8(QUAD8_CHAN_OP_RESET_COUNTERS, &priv->reg->channel_oper);
+ /* Set initial configuration for all counters */
+- for (i = 0; i < QUAD8_NUM_COUNTERS; i++) {
+- base_offset = base[id] + 2 * i;
+- /* Reset Byte Pointer */
+- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
+- /* Reset filter clock factor */
+- outb(0, base_offset);
+- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC,
+- base_offset + 1);
+- /* Reset Byte Pointer */
+- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
+- /* Reset Preset Register */
+- for (j = 0; j < 3; j++)
+- outb(0x00, base_offset);
+- /* Reset Borrow, Carry, Compare, and Sign flags */
+- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1);
+- /* Reset Error flag */
+- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1);
+- /* Binary encoding; Normal count; non-quadrature mode */
+- outb(QUAD8_CTR_CMR, base_offset + 1);
+- /* Disable A and B inputs; preset on index; FLG1 as Carry */
+- outb(QUAD8_CTR_IOR, base_offset + 1);
+- /* Disable index function; negative index polarity */
+- outb(QUAD8_CTR_IDR, base_offset + 1);
+- }
++ for (i = 0; i < QUAD8_NUM_COUNTERS; i++)
++ quad8_init_counter(priv->reg->channel + i);
+ /* Disable Differential Encoder Cable Status for all channels */
+- outb(0xFF, base[id] + QUAD8_DIFF_ENCODER_CABLE_STATUS);
++ iowrite8(0xFF, &priv->reg->cable_status);
+ /* Enable all counters and enable interrupt function */
+- outb(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, base[id] + QUAD8_REG_CHAN_OP);
++ iowrite8(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, &priv->reg->channel_oper);
+
+ err = devm_request_irq(&counter->dev, irq[id], quad8_irq_handler,
+ IRQF_SHARED, counter->name, counter);
+diff --git a/drivers/firmware/arm_scmi/scmi_pm_domain.c b/drivers/firmware/arm_scmi/scmi_pm_domain.c
+index 581d34c957695..d5dee625de780 100644
+--- a/drivers/firmware/arm_scmi/scmi_pm_domain.c
++++ b/drivers/firmware/arm_scmi/scmi_pm_domain.c
+@@ -8,7 +8,6 @@
+ #include <linux/err.h>
+ #include <linux/io.h>
+ #include <linux/module.h>
+-#include <linux/pm_clock.h>
+ #include <linux/pm_domain.h>
+ #include <linux/scmi_protocol.h>
+
+@@ -53,27 +52,6 @@ static int scmi_pd_power_off(struct generic_pm_domain *domain)
+ return scmi_pd_power(domain, false);
+ }
+
+-static int scmi_pd_attach_dev(struct generic_pm_domain *pd, struct device *dev)
+-{
+- int ret;
+-
+- ret = pm_clk_create(dev);
+- if (ret)
+- return ret;
+-
+- ret = of_pm_clk_add_clks(dev);
+- if (ret >= 0)
+- return 0;
+-
+- pm_clk_destroy(dev);
+- return ret;
+-}
+-
+-static void scmi_pd_detach_dev(struct generic_pm_domain *pd, struct device *dev)
+-{
+- pm_clk_destroy(dev);
+-}
+-
+ static int scmi_pm_domain_probe(struct scmi_device *sdev)
+ {
+ int num_domains, i;
+@@ -124,10 +102,6 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev)
+ scmi_pd->genpd.name = scmi_pd->name;
+ scmi_pd->genpd.power_off = scmi_pd_power_off;
+ scmi_pd->genpd.power_on = scmi_pd_power_on;
+- scmi_pd->genpd.attach_dev = scmi_pd_attach_dev;
+- scmi_pd->genpd.detach_dev = scmi_pd_detach_dev;
+- scmi_pd->genpd.flags = GENPD_FLAG_PM_CLK |
+- GENPD_FLAG_ACTIVE_WAKEUP;
+
+ pm_genpd_init(&scmi_pd->genpd, NULL,
+ state == SCMI_POWER_STATE_GENERIC_OFF);
+diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
+index 2db19cd640a43..de1e7a1a76f2e 100644
+--- a/drivers/gpio/gpio-mvebu.c
++++ b/drivers/gpio/gpio-mvebu.c
+@@ -793,8 +793,12 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
+ u32 offset;
+ u32 set;
+
+- if (of_device_is_compatible(mvchip->chip.of_node,
+- "marvell,armada-370-gpio")) {
++ if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) {
++ int ret = of_property_read_u32(dev->of_node,
++ "marvell,pwm-offset", &offset);
++ if (ret < 0)
++ return 0;
++ } else {
+ /*
+ * There are only two sets of PWM configuration registers for
+ * all the GPIO lines on those SoCs which this driver reserves
+@@ -804,13 +808,6 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
+ if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm"))
+ return 0;
+ offset = 0;
+- } else if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) {
+- int ret = of_property_read_u32(dev->of_node,
+- "marvell,pwm-offset", &offset);
+- if (ret < 0)
+- return 0;
+- } else {
+- return 0;
+ }
+
+ if (IS_ERR(mvchip->clk))
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+index 98ac53ee6bb55..6cded09d5878a 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+@@ -1056,6 +1056,10 @@ bool amdgpu_acpi_should_gpu_reset(struct amdgpu_device *adev)
+ {
+ if (adev->flags & AMD_IS_APU)
+ return false;
++
++ if (amdgpu_sriov_vf(adev))
++ return false;
++
+ return pm_suspend_target_state != PM_SUSPEND_TO_IDLE;
+ }
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+index 929f8b75bfaee..53b07b091e823 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+@@ -3178,7 +3178,8 @@ static int amdgpu_device_ip_resume_phase1(struct amdgpu_device *adev)
+ continue;
+ if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON ||
+ adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC ||
+- adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH) {
++ adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH ||
++ (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP && amdgpu_sriov_vf(adev))) {
+
+ r = adev->ip_blocks[i].version->funcs->resume(adev);
+ if (r) {
+@@ -4124,12 +4125,20 @@ static void amdgpu_device_evict_resources(struct amdgpu_device *adev)
+ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon)
+ {
+ struct amdgpu_device *adev = drm_to_adev(dev);
++ int r = 0;
+
+ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+ return 0;
+
+ adev->in_suspend = true;
+
++ if (amdgpu_sriov_vf(adev)) {
++ amdgpu_virt_fini_data_exchange(adev);
++ r = amdgpu_virt_request_full_gpu(adev, false);
++ if (r)
++ return r;
++ }
++
+ if (amdgpu_acpi_smart_shift_update(dev, AMDGPU_SS_DEV_D3))
+ DRM_WARN("smart shift update failed\n");
+
+@@ -4153,6 +4162,9 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon)
+
+ amdgpu_device_ip_suspend_phase2(adev);
+
++ if (amdgpu_sriov_vf(adev))
++ amdgpu_virt_release_full_gpu(adev, false);
++
+ return 0;
+ }
+
+@@ -4171,6 +4183,12 @@ int amdgpu_device_resume(struct drm_device *dev, bool fbcon)
+ struct amdgpu_device *adev = drm_to_adev(dev);
+ int r = 0;
+
++ if (amdgpu_sriov_vf(adev)) {
++ r = amdgpu_virt_request_full_gpu(adev, true);
++ if (r)
++ return r;
++ }
++
+ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+ return 0;
+
+@@ -4185,6 +4203,13 @@ int amdgpu_device_resume(struct drm_device *dev, bool fbcon)
+ }
+
+ r = amdgpu_device_ip_resume(adev);
++
++ /* no matter what r is, always need to properly release full GPU */
++ if (amdgpu_sriov_vf(adev)) {
++ amdgpu_virt_init_data_exchange(adev);
++ amdgpu_virt_release_full_gpu(adev, true);
++ }
++
+ if (r) {
+ dev_err(adev->dev, "amdgpu_device_ip_resume failed (%d).\n", r);
+ return r;
+diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+index 01c8b80e34ec4..41431b9d55bd9 100644
+--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
++++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+@@ -1863,12 +1863,6 @@ EXPORT_SYMBOL_GPL(analogix_dp_remove);
+ int analogix_dp_suspend(struct analogix_dp_device *dp)
+ {
+ clk_disable_unprepare(dp->clock);
+-
+- if (dp->plat_data->panel) {
+- if (drm_panel_unprepare(dp->plat_data->panel))
+- DRM_ERROR("failed to turnoff the panel\n");
+- }
+-
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(analogix_dp_suspend);
+@@ -1883,13 +1877,6 @@ int analogix_dp_resume(struct analogix_dp_device *dp)
+ return ret;
+ }
+
+- if (dp->plat_data->panel) {
+- if (drm_panel_prepare(dp->plat_data->panel)) {
+- DRM_ERROR("failed to setup the panel\n");
+- return -EBUSY;
+- }
+- }
+-
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(analogix_dp_resume);
+diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c
+index c642d1e02b2f8..167cd7d85dbbb 100644
+--- a/drivers/gpu/drm/bridge/lontium-lt8912b.c
++++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c
+@@ -186,7 +186,7 @@ static int lt8912_write_lvds_config(struct lt8912 *lt)
+ {0x03, 0xff},
+ };
+
+- return regmap_multi_reg_write(lt->regmap[I2C_CEC_DSI], seq, ARRAY_SIZE(seq));
++ return regmap_multi_reg_write(lt->regmap[I2C_MAIN], seq, ARRAY_SIZE(seq));
+ };
+
+ static inline struct lt8912 *bridge_to_lt8912(struct drm_bridge *b)
+@@ -266,7 +266,7 @@ static int lt8912_video_setup(struct lt8912 *lt)
+ u32 hactive, h_total, hpw, hfp, hbp;
+ u32 vactive, v_total, vpw, vfp, vbp;
+ u8 settle = 0x08;
+- int ret;
++ int ret, hsync_activehigh, vsync_activehigh;
+
+ if (!lt)
+ return -EINVAL;
+@@ -276,12 +276,14 @@ static int lt8912_video_setup(struct lt8912 *lt)
+ hpw = lt->mode.hsync_len;
+ hbp = lt->mode.hback_porch;
+ h_total = hactive + hfp + hpw + hbp;
++ hsync_activehigh = lt->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH;
+
+ vactive = lt->mode.vactive;
+ vfp = lt->mode.vfront_porch;
+ vpw = lt->mode.vsync_len;
+ vbp = lt->mode.vback_porch;
+ v_total = vactive + vfp + vpw + vbp;
++ vsync_activehigh = lt->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH;
+
+ if (vactive <= 600)
+ settle = 0x04;
+@@ -315,6 +317,13 @@ static int lt8912_video_setup(struct lt8912 *lt)
+ ret |= regmap_write(lt->regmap[I2C_CEC_DSI], 0x3e, hfp & 0xff);
+ ret |= regmap_write(lt->regmap[I2C_CEC_DSI], 0x3f, hfp >> 8);
+
++ ret |= regmap_update_bits(lt->regmap[I2C_MAIN], 0xab, BIT(0),
++ vsync_activehigh ? BIT(0) : 0);
++ ret |= regmap_update_bits(lt->regmap[I2C_MAIN], 0xab, BIT(1),
++ hsync_activehigh ? BIT(1) : 0);
++ ret |= regmap_update_bits(lt->regmap[I2C_MAIN], 0xb2, BIT(0),
++ lt->connector.display_info.is_hdmi ? BIT(0) : 0);
++
+ return ret;
+ }
+
+diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h
+index 298f2cc7a879f..3ca0ae5ed1fb4 100644
+--- a/drivers/gpu/drm/i915/gt/intel_engine_types.h
++++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h
+@@ -155,6 +155,21 @@ struct intel_engine_execlists {
+ */
+ struct timer_list preempt;
+
++ /**
++ * @preempt_target: active request at the time of the preemption request
++ *
++ * We force a preemption to occur if the pending contexts have not
++ * been promoted to active upon receipt of the CS ack event within
++ * the timeout. This timeout maybe chosen based on the target,
++ * using a very short timeout if the context is no longer schedulable.
++ * That short timeout may not be applicable to other contexts, so
++ * if a context switch should happen within before the preemption
++ * timeout, we may shoot early at an innocent context. To prevent this,
++ * we record which context was active at the time of the preemption
++ * request and only reset that context upon the timeout.
++ */
++ const struct i915_request *preempt_target;
++
+ /**
+ * @ccid: identifier for contexts submitted to this engine
+ */
+diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+index 0627fa10d2dcb..277f9d6551f44 100644
+--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
++++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+@@ -1241,6 +1241,9 @@ static unsigned long active_preempt_timeout(struct intel_engine_cs *engine,
+ if (!rq)
+ return 0;
+
++ /* Only allow ourselves to force reset the currently active context */
++ engine->execlists.preempt_target = rq;
++
+ /* Force a fast reset for terminated contexts (ignoring sysfs!) */
+ if (unlikely(intel_context_is_banned(rq->context) || bad_request(rq)))
+ return 1;
+@@ -2427,8 +2430,24 @@ static void execlists_submission_tasklet(struct tasklet_struct *t)
+ GEM_BUG_ON(inactive - post > ARRAY_SIZE(post));
+
+ if (unlikely(preempt_timeout(engine))) {
++ const struct i915_request *rq = *engine->execlists.active;
++
++ /*
++ * If after the preempt-timeout expired, we are still on the
++ * same active request/context as before we initiated the
++ * preemption, reset the engine.
++ *
++ * However, if we have processed a CS event to switch contexts,
++ * but not yet processed the CS event for the pending
++ * preemption, reset the timer allowing the new context to
++ * gracefully exit.
++ */
+ cancel_timer(&engine->execlists.preempt);
+- engine->execlists.error_interrupt |= ERROR_PREEMPT;
++ if (rq == engine->execlists.preempt_target)
++ engine->execlists.error_interrupt |= ERROR_PREEMPT;
++ else
++ set_timer_ms(&engine->execlists.preempt,
++ active_preempt_timeout(engine, rq));
+ }
+
+ if (unlikely(READ_ONCE(engine->execlists.error_interrupt))) {
+diff --git a/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c
+index f76b6cf8040ec..b8cb58e2819a5 100644
+--- a/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c
++++ b/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c
+@@ -544,8 +544,7 @@ static INTEL_GT_RPS_BOOL_ATTR_RO(throttle_reason_ratl, RATL_MASK);
+ static INTEL_GT_RPS_BOOL_ATTR_RO(throttle_reason_vr_thermalert, VR_THERMALERT_MASK);
+ static INTEL_GT_RPS_BOOL_ATTR_RO(throttle_reason_vr_tdc, VR_TDC_MASK);
+
+-static const struct attribute *freq_attrs[] = {
+- &dev_attr_punit_req_freq_mhz.attr,
++static const struct attribute *throttle_reason_attrs[] = {
+ &attr_throttle_reason_status.attr,
+ &attr_throttle_reason_pl1.attr,
+ &attr_throttle_reason_pl2.attr,
+@@ -594,9 +593,17 @@ void intel_gt_sysfs_pm_init(struct intel_gt *gt, struct kobject *kobj)
+ if (!is_object_gt(kobj))
+ return;
+
+- ret = sysfs_create_files(kobj, freq_attrs);
++ ret = sysfs_create_file(kobj, &dev_attr_punit_req_freq_mhz.attr);
+ if (ret)
+ drm_warn(&gt->i915->drm,
+- "failed to create gt%u throttle sysfs files (%pe)",
++ "failed to create gt%u punit_req_freq_mhz sysfs (%pe)",
+ gt->info.id, ERR_PTR(ret));
++
++ if (GRAPHICS_VER(gt->i915) >= 11) {
++ ret = sysfs_create_files(kobj, throttle_reason_attrs);
++ if (ret)
++ drm_warn(&gt->i915->drm,
++ "failed to create gt%u throttle sysfs files (%pe)",
++ gt->info.id, ERR_PTR(ret));
++ }
+ }
+diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c
+index 65286762b02ab..ad8660be0127c 100644
+--- a/drivers/input/keyboard/snvs_pwrkey.c
++++ b/drivers/input/keyboard/snvs_pwrkey.c
+@@ -20,7 +20,7 @@
+ #include <linux/mfd/syscon.h>
+ #include <linux/regmap.h>
+
+-#define SNVS_HPVIDR1_REG 0xF8
++#define SNVS_HPVIDR1_REG 0xBF8
+ #define SNVS_LPSR_REG 0x4C /* LP Status Register */
+ #define SNVS_LPCR_REG 0x38 /* LP Control Register */
+ #define SNVS_HPSR_REG 0x14
+diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c
+index 2745bf1aee381..83f4be05e27b6 100644
+--- a/drivers/input/touchscreen/melfas_mip4.c
++++ b/drivers/input/touchscreen/melfas_mip4.c
+@@ -1453,7 +1453,7 @@ static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id)
+ "ce", GPIOD_OUT_LOW);
+ if (IS_ERR(ts->gpio_ce)) {
+ error = PTR_ERR(ts->gpio_ce);
+- if (error != EPROBE_DEFER)
++ if (error != -EPROBE_DEFER)
+ dev_err(&client->dev,
+ "Failed to get gpio: %d\n", error);
+ return error;
+diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c
+index a1bd6d9c9223c..909df82fed332 100644
+--- a/drivers/media/dvb-core/dvb_vb2.c
++++ b/drivers/media/dvb-core/dvb_vb2.c
+@@ -354,6 +354,12 @@ int dvb_vb2_reqbufs(struct dvb_vb2_ctx *ctx, struct dmx_requestbuffers *req)
+
+ int dvb_vb2_querybuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
+ {
++ struct vb2_queue *q = &ctx->vb_q;
++
++ if (b->index >= q->num_buffers) {
++ dprintk(1, "[%s] buffer index out of range\n", ctx->name);
++ return -EINVAL;
++ }
+ vb2_core_querybuf(&ctx->vb_q, b->index, b);
+ dprintk(3, "[%s] index=%d\n", ctx->name, b->index);
+ return 0;
+@@ -378,8 +384,13 @@ int dvb_vb2_expbuf(struct dvb_vb2_ctx *ctx, struct dmx_exportbuffer *exp)
+
+ int dvb_vb2_qbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
+ {
++ struct vb2_queue *q = &ctx->vb_q;
+ int ret;
+
++ if (b->index >= q->num_buffers) {
++ dprintk(1, "[%s] buffer index out of range\n", ctx->name);
++ return -EINVAL;
++ }
+ ret = vb2_core_qbuf(&ctx->vb_q, b->index, b, NULL);
+ if (ret) {
+ dprintk(1, "[%s] index=%d errno=%d\n", ctx->name,
+diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c
+index 95e8c29ccc651..d2f5f30582a9c 100644
+--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c
++++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c
+@@ -228,7 +228,6 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
+ {
+ struct mtk_vcodec_dev *dev;
+ struct video_device *vfd_enc;
+- struct resource *res;
+ phandle rproc_phandle;
+ enum mtk_vcodec_fw_type fw_type;
+ int ret;
+@@ -272,14 +271,12 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
+ goto err_res;
+ }
+
+- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+- if (res == NULL) {
+- dev_err(&pdev->dev, "failed to get irq resource");
+- ret = -ENOENT;
++ dev->enc_irq = platform_get_irq(pdev, 0);
++ if (dev->enc_irq < 0) {
++ ret = dev->enc_irq;
+ goto err_res;
+ }
+
+- dev->enc_irq = platform_get_irq(pdev, 0);
+ irq_set_status_flags(dev->enc_irq, IRQ_NOAUTOEN);
+ ret = devm_request_irq(&pdev->dev, dev->enc_irq,
+ mtk_vcodec_enc_irq_handler,
+diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+index 0f3d6b5667b07..55c26e7d370e9 100644
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -1040,6 +1040,8 @@ int v4l2_compat_get_array_args(struct file *file, void *mbuf,
+ {
+ int err = 0;
+
++ memset(mbuf, 0, array_size);
++
+ switch (cmd) {
+ case VIDIOC_G_FMT32:
+ case VIDIOC_S_FMT32:
+diff --git a/drivers/mmc/host/mmc_hsq.c b/drivers/mmc/host/mmc_hsq.c
+index a5e05ed0fda3e..9d35453e7371b 100644
+--- a/drivers/mmc/host/mmc_hsq.c
++++ b/drivers/mmc/host/mmc_hsq.c
+@@ -34,7 +34,7 @@ static void mmc_hsq_pump_requests(struct mmc_hsq *hsq)
+ spin_lock_irqsave(&hsq->lock, flags);
+
+ /* Make sure we are not already running a request now */
+- if (hsq->mrq) {
++ if (hsq->mrq || hsq->recovery_halt) {
+ spin_unlock_irqrestore(&hsq->lock, flags);
+ return;
+ }
+diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c
+index b6eb75f4bbfc6..dfc3ffd5b1f8c 100644
+--- a/drivers/mmc/host/moxart-mmc.c
++++ b/drivers/mmc/host/moxart-mmc.c
+@@ -111,8 +111,8 @@
+ #define CLK_DIV_MASK 0x7f
+
+ /* REG_BUS_WIDTH */
+-#define BUS_WIDTH_8 BIT(2)
+-#define BUS_WIDTH_4 BIT(1)
++#define BUS_WIDTH_4_SUPPORT BIT(3)
++#define BUS_WIDTH_4 BIT(2)
+ #define BUS_WIDTH_1 BIT(0)
+
+ #define MMC_VDD_360 23
+@@ -524,9 +524,6 @@ static void moxart_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+ case MMC_BUS_WIDTH_4:
+ writel(BUS_WIDTH_4, host->base + REG_BUS_WIDTH);
+ break;
+- case MMC_BUS_WIDTH_8:
+- writel(BUS_WIDTH_8, host->base + REG_BUS_WIDTH);
+- break;
+ default:
+ writel(BUS_WIDTH_1, host->base + REG_BUS_WIDTH);
+ break;
+@@ -651,16 +648,8 @@ static int moxart_probe(struct platform_device *pdev)
+ dmaengine_slave_config(host->dma_chan_rx, &cfg);
+ }
+
+- switch ((readl(host->base + REG_BUS_WIDTH) >> 3) & 3) {
+- case 1:
++ if (readl(host->base + REG_BUS_WIDTH) & BUS_WIDTH_4_SUPPORT)
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+- break;
+- case 2:
+- mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
+- break;
+- default:
+- break;
+- }
+
+ writel(0, host->base + REG_INTERRUPT_MASK);
+
+diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h
+index bd2f6dc011941..e33d5a9676944 100644
+--- a/drivers/net/can/c_can/c_can.h
++++ b/drivers/net/can/c_can/c_can.h
+@@ -235,9 +235,22 @@ static inline u8 c_can_get_tx_tail(const struct c_can_tx_ring *ring)
+ return ring->tail & (ring->obj_num - 1);
+ }
+
+-static inline u8 c_can_get_tx_free(const struct c_can_tx_ring *ring)
++static inline u8 c_can_get_tx_free(const struct c_can_priv *priv,
++ const struct c_can_tx_ring *ring)
+ {
+- return ring->obj_num - (ring->head - ring->tail);
++ u8 head = c_can_get_tx_head(ring);
++ u8 tail = c_can_get_tx_tail(ring);
++
++ if (priv->type == BOSCH_D_CAN)
++ return ring->obj_num - (ring->head - ring->tail);
++
++ /* This is not a FIFO. C/D_CAN sends out the buffers
++ * prioritized. The lowest buffer number wins.
++ */
++ if (head < tail)
++ return 0;
++
++ return ring->obj_num - head;
+ }
+
+ #endif /* C_CAN_H */
+diff --git a/drivers/net/can/c_can/c_can_main.c b/drivers/net/can/c_can/c_can_main.c
+index a7362af0babb6..b42264dd7addd 100644
+--- a/drivers/net/can/c_can/c_can_main.c
++++ b/drivers/net/can/c_can/c_can_main.c
+@@ -429,7 +429,7 @@ static void c_can_setup_receive_object(struct net_device *dev, int iface,
+ static bool c_can_tx_busy(const struct c_can_priv *priv,
+ const struct c_can_tx_ring *tx_ring)
+ {
+- if (c_can_get_tx_free(tx_ring) > 0)
++ if (c_can_get_tx_free(priv, tx_ring) > 0)
+ return false;
+
+ netif_stop_queue(priv->dev);
+@@ -437,7 +437,7 @@ static bool c_can_tx_busy(const struct c_can_priv *priv,
+ /* Memory barrier before checking tx_free (head and tail) */
+ smp_mb();
+
+- if (c_can_get_tx_free(tx_ring) == 0) {
++ if (c_can_get_tx_free(priv, tx_ring) == 0) {
+ netdev_dbg(priv->dev,
+ "Stopping tx-queue (tx_head=0x%08x, tx_tail=0x%08x, len=%d).\n",
+ tx_ring->head, tx_ring->tail,
+@@ -465,7 +465,7 @@ static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
+
+ idx = c_can_get_tx_head(tx_ring);
+ tx_ring->head++;
+- if (c_can_get_tx_free(tx_ring) == 0)
++ if (c_can_get_tx_free(priv, tx_ring) == 0)
+ netif_stop_queue(dev);
+
+ if (idx < c_can_get_tx_tail(tx_ring))
+@@ -748,7 +748,7 @@ static void c_can_do_tx(struct net_device *dev)
+ return;
+
+ tx_ring->tail += pkts;
+- if (c_can_get_tx_free(tx_ring)) {
++ if (c_can_get_tx_free(priv, tx_ring)) {
+ /* Make sure that anybody stopping the queue after
+ * this sees the new tx_ring->tail.
+ */
+@@ -760,8 +760,7 @@ static void c_can_do_tx(struct net_device *dev)
+ stats->tx_packets += pkts;
+
+ tail = c_can_get_tx_tail(tx_ring);
+-
+- if (tail == 0) {
++ if (priv->type == BOSCH_D_CAN && tail == 0) {
+ u8 head = c_can_get_tx_head(tx_ring);
+
+ /* Start transmission for all cached messages */
+diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
+index 2b02d823d4977..c2d452a75355c 100644
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -506,14 +506,19 @@ static bool mt7531_dual_sgmii_supported(struct mt7530_priv *priv)
+ static int
+ mt7531_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
+ {
+- struct mt7530_priv *priv = ds->priv;
++ return 0;
++}
++
++static void
++mt7531_pll_setup(struct mt7530_priv *priv)
++{
+ u32 top_sig;
+ u32 hwstrap;
+ u32 xtal;
+ u32 val;
+
+ if (mt7531_dual_sgmii_supported(priv))
+- return 0;
++ return;
+
+ val = mt7530_read(priv, MT7531_CREV);
+ top_sig = mt7530_read(priv, MT7531_TOP_SIG_SR);
+@@ -592,8 +597,6 @@ mt7531_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
+ val |= EN_COREPLL;
+ mt7530_write(priv, MT7531_PLLGP_EN, val);
+ usleep_range(25, 35);
+-
+- return 0;
+ }
+
+ static void
+@@ -2310,6 +2313,8 @@ mt7531_setup(struct dsa_switch *ds)
+ SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
+ SYS_CTRL_REG_RST);
+
++ mt7531_pll_setup(priv);
++
+ if (mt7531_dual_sgmii_supported(priv)) {
+ priv->p5_intf_sel = P5_INTF_SEL_GMAC5_SGMII;
+
+@@ -2863,8 +2868,6 @@ mt7531_cpu_port_config(struct dsa_switch *ds, int port)
+ case 6:
+ interface = PHY_INTERFACE_MODE_2500BASEX;
+
+- mt7531_pad_setup(ds, interface);
+-
+ priv->p6_interface = interface;
+ break;
+ default:
+diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
+index d89098f4ede80..e9aa41949a4b7 100644
+--- a/drivers/net/ethernet/cadence/macb_main.c
++++ b/drivers/net/ethernet/cadence/macb_main.c
+@@ -5092,6 +5092,7 @@ static int __maybe_unused macb_suspend(struct device *dev)
+ if (!(bp->wol & MACB_WOL_ENABLED)) {
+ rtnl_lock();
+ phylink_stop(bp->phylink);
++ phy_exit(bp->sgmii_phy);
+ rtnl_unlock();
+ spin_lock_irqsave(&bp->lock, flags);
+ macb_reset_hw(bp);
+@@ -5181,6 +5182,9 @@ static int __maybe_unused macb_resume(struct device *dev)
+ macb_set_rx_mode(netdev);
+ macb_restore_features(bp);
+ rtnl_lock();
++ if (!device_may_wakeup(&bp->dev->dev))
++ phy_init(bp->sgmii_phy);
++
+ phylink_start(bp->phylink);
+ rtnl_unlock();
+
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+index a7f291c897021..557c591a6ce3a 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+@@ -14,6 +14,7 @@
+ #include "cudbg_entity.h"
+ #include "cudbg_lib.h"
+ #include "cudbg_zlib.h"
++#include "cxgb4_tc_mqprio.h"
+
+ static const u32 t6_tp_pio_array[][IREG_NUM_ELEM] = {
+ {0x7e40, 0x7e44, 0x020, 28}, /* t6_tp_pio_regs_20_to_3b */
+@@ -3458,7 +3459,7 @@ int cudbg_collect_qdesc(struct cudbg_init *pdbg_init,
+ for (i = 0; i < utxq->ntxq; i++)
+ QDESC_GET_TXQ(&utxq->uldtxq[i].q,
+ cudbg_uld_txq_to_qtype(j),
+- out_unlock);
++ out_unlock_uld);
+ }
+ }
+
+@@ -3475,7 +3476,7 @@ int cudbg_collect_qdesc(struct cudbg_init *pdbg_init,
+ for (i = 0; i < urxq->nrxq; i++)
+ QDESC_GET_RXQ(&urxq->uldrxq[i].rspq,
+ cudbg_uld_rxq_to_qtype(j),
+- out_unlock);
++ out_unlock_uld);
+ }
+
+ /* ULD FLQ */
+@@ -3487,7 +3488,7 @@ int cudbg_collect_qdesc(struct cudbg_init *pdbg_init,
+ for (i = 0; i < urxq->nrxq; i++)
+ QDESC_GET_FLQ(&urxq->uldrxq[i].fl,
+ cudbg_uld_flq_to_qtype(j),
+- out_unlock);
++ out_unlock_uld);
+ }
+
+ /* ULD CIQ */
+@@ -3500,29 +3501,34 @@ int cudbg_collect_qdesc(struct cudbg_init *pdbg_init,
+ for (i = 0; i < urxq->nciq; i++)
+ QDESC_GET_RXQ(&urxq->uldrxq[base + i].rspq,
+ cudbg_uld_ciq_to_qtype(j),
+- out_unlock);
++ out_unlock_uld);
+ }
+ }
++ mutex_unlock(&uld_mutex);
++
++ if (!padap->tc_mqprio)
++ goto out;
+
++ mutex_lock(&padap->tc_mqprio->mqprio_mutex);
+ /* ETHOFLD TXQ */
+ if (s->eohw_txq)
+ for (i = 0; i < s->eoqsets; i++)
+ QDESC_GET_TXQ(&s->eohw_txq[i].q,
+- CUDBG_QTYPE_ETHOFLD_TXQ, out);
++ CUDBG_QTYPE_ETHOFLD_TXQ, out_unlock_mqprio);
+
+ /* ETHOFLD RXQ and FLQ */
+ if (s->eohw_rxq) {
+ for (i = 0; i < s->eoqsets; i++)
+ QDESC_GET_RXQ(&s->eohw_rxq[i].rspq,
+- CUDBG_QTYPE_ETHOFLD_RXQ, out);
++ CUDBG_QTYPE_ETHOFLD_RXQ, out_unlock_mqprio);
+
+ for (i = 0; i < s->eoqsets; i++)
+ QDESC_GET_FLQ(&s->eohw_rxq[i].fl,
+- CUDBG_QTYPE_ETHOFLD_FLQ, out);
++ CUDBG_QTYPE_ETHOFLD_FLQ, out_unlock_mqprio);
+ }
+
+-out_unlock:
+- mutex_unlock(&uld_mutex);
++out_unlock_mqprio:
++ mutex_unlock(&padap->tc_mqprio->mqprio_mutex);
+
+ out:
+ qdesc_info->qdesc_entry_size = sizeof(*qdesc_entry);
+@@ -3559,6 +3565,10 @@ out_free:
+ #undef QDESC_GET
+
+ return rc;
++
++out_unlock_uld:
++ mutex_unlock(&uld_mutex);
++ goto out;
+ }
+
+ int cudbg_collect_flash(struct cudbg_init *pdbg_init,
+diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
+index 97453d1dfafed..dd2285d4bef47 100644
+--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
++++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
+@@ -1467,7 +1467,7 @@ int ice_napi_poll(struct napi_struct *napi, int budget)
+ bool wd;
+
+ if (tx_ring->xsk_pool)
+- wd = ice_xmit_zc(tx_ring, ICE_DESC_UNUSED(tx_ring), budget);
++ wd = ice_xmit_zc(tx_ring);
+ else if (ice_ring_is_xdp(tx_ring))
+ wd = true;
+ else
+diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c
+index 03ce85f6e6df8..056c904b83ccb 100644
+--- a/drivers/net/ethernet/intel/ice/ice_xsk.c
++++ b/drivers/net/ethernet/intel/ice/ice_xsk.c
+@@ -392,13 +392,6 @@ int ice_xsk_pool_setup(struct ice_vsi *vsi, struct xsk_buff_pool *pool, u16 qid)
+ goto failure;
+ }
+
+- if (!is_power_of_2(vsi->rx_rings[qid]->count) ||
+- !is_power_of_2(vsi->tx_rings[qid]->count)) {
+- netdev_err(vsi->netdev, "Please align ring sizes to power of 2\n");
+- pool_failure = -EINVAL;
+- goto failure;
+- }
+-
+ if_running = netif_running(vsi->netdev) && ice_is_xdp_ena_vsi(vsi);
+
+ if (if_running) {
+@@ -534,11 +527,10 @@ exit:
+ bool ice_alloc_rx_bufs_zc(struct ice_rx_ring *rx_ring, u16 count)
+ {
+ u16 rx_thresh = ICE_RING_QUARTER(rx_ring);
+- u16 batched, leftover, i, tail_bumps;
++ u16 leftover, i, tail_bumps;
+
+- batched = ALIGN_DOWN(count, rx_thresh);
+- tail_bumps = batched / rx_thresh;
+- leftover = count & (rx_thresh - 1);
++ tail_bumps = count / rx_thresh;
++ leftover = count - (tail_bumps * rx_thresh);
+
+ for (i = 0; i < tail_bumps; i++)
+ if (!__ice_alloc_rx_bufs_zc(rx_ring, rx_thresh))
+@@ -788,69 +780,57 @@ ice_clean_xdp_tx_buf(struct ice_tx_ring *xdp_ring, struct ice_tx_buf *tx_buf)
+ }
+
+ /**
+- * ice_clean_xdp_irq_zc - Reclaim resources after transmit completes on XDP ring
+- * @xdp_ring: XDP ring to clean
+- * @napi_budget: amount of descriptors that NAPI allows us to clean
+- *
+- * Returns count of cleaned descriptors
++ * ice_clean_xdp_irq_zc - produce AF_XDP descriptors to CQ
++ * @xdp_ring: XDP Tx ring
+ */
+-static u16 ice_clean_xdp_irq_zc(struct ice_tx_ring *xdp_ring, int napi_budget)
++static void ice_clean_xdp_irq_zc(struct ice_tx_ring *xdp_ring)
+ {
+- u16 tx_thresh = ICE_RING_QUARTER(xdp_ring);
+- int budget = napi_budget / tx_thresh;
+- u16 next_dd = xdp_ring->next_dd;
+- u16 ntc, cleared_dds = 0;
+-
+- do {
+- struct ice_tx_desc *next_dd_desc;
+- u16 desc_cnt = xdp_ring->count;
+- struct ice_tx_buf *tx_buf;
+- u32 xsk_frames;
+- u16 i;
+-
+- next_dd_desc = ICE_TX_DESC(xdp_ring, next_dd);
+- if (!(next_dd_desc->cmd_type_offset_bsz &
+- cpu_to_le64(ICE_TX_DESC_DTYPE_DESC_DONE)))
+- break;
++ u16 ntc = xdp_ring->next_to_clean;
++ struct ice_tx_desc *tx_desc;
++ u16 cnt = xdp_ring->count;
++ struct ice_tx_buf *tx_buf;
++ u16 xsk_frames = 0;
++ u16 last_rs;
++ int i;
+
+- cleared_dds++;
+- xsk_frames = 0;
+- if (likely(!xdp_ring->xdp_tx_active)) {
+- xsk_frames = tx_thresh;
+- goto skip;
+- }
++ last_rs = xdp_ring->next_to_use ? xdp_ring->next_to_use - 1 : cnt - 1;
++ tx_desc = ICE_TX_DESC(xdp_ring, last_rs);
++ if ((tx_desc->cmd_type_offset_bsz &
++ cpu_to_le64(ICE_TX_DESC_DTYPE_DESC_DONE))) {
++ if (last_rs >= ntc)
++ xsk_frames = last_rs - ntc + 1;
++ else
++ xsk_frames = last_rs + cnt - ntc + 1;
++ }
+
+- ntc = xdp_ring->next_to_clean;
++ if (!xsk_frames)
++ return;
+
+- for (i = 0; i < tx_thresh; i++) {
+- tx_buf = &xdp_ring->tx_buf[ntc];
++ if (likely(!xdp_ring->xdp_tx_active))
++ goto skip;
+
+- if (tx_buf->raw_buf) {
+- ice_clean_xdp_tx_buf(xdp_ring, tx_buf);
+- tx_buf->raw_buf = NULL;
+- } else {
+- xsk_frames++;
+- }
++ ntc = xdp_ring->next_to_clean;
++ for (i = 0; i < xsk_frames; i++) {
++ tx_buf = &xdp_ring->tx_buf[ntc];
+
+- ntc++;
+- if (ntc >= xdp_ring->count)
+- ntc = 0;
++ if (tx_buf->raw_buf) {
++ ice_clean_xdp_tx_buf(xdp_ring, tx_buf);
++ tx_buf->raw_buf = NULL;
++ } else {
++ xsk_frames++;
+ }
++
++ ntc++;
++ if (ntc >= xdp_ring->count)
++ ntc = 0;
++ }
+ skip:
+- xdp_ring->next_to_clean += tx_thresh;
+- if (xdp_ring->next_to_clean >= desc_cnt)
+- xdp_ring->next_to_clean -= desc_cnt;
+- if (xsk_frames)
+- xsk_tx_completed(xdp_ring->xsk_pool, xsk_frames);
+- next_dd_desc->cmd_type_offset_bsz = 0;
+- next_dd = next_dd + tx_thresh;
+- if (next_dd >= desc_cnt)
+- next_dd = tx_thresh - 1;
+- } while (--budget);
+-
+- xdp_ring->next_dd = next_dd;
+-
+- return cleared_dds * tx_thresh;
++ tx_desc->cmd_type_offset_bsz = 0;
++ xdp_ring->next_to_clean += xsk_frames;
++ if (xdp_ring->next_to_clean >= cnt)
++ xdp_ring->next_to_clean -= cnt;
++ if (xsk_frames)
++ xsk_tx_completed(xdp_ring->xsk_pool, xsk_frames);
+ }
+
+ /**
+@@ -885,7 +865,6 @@ static void ice_xmit_pkt(struct ice_tx_ring *xdp_ring, struct xdp_desc *desc,
+ static void ice_xmit_pkt_batch(struct ice_tx_ring *xdp_ring, struct xdp_desc *descs,
+ unsigned int *total_bytes)
+ {
+- u16 tx_thresh = ICE_RING_QUARTER(xdp_ring);
+ u16 ntu = xdp_ring->next_to_use;
+ struct ice_tx_desc *tx_desc;
+ u32 i;
+@@ -905,13 +884,6 @@ static void ice_xmit_pkt_batch(struct ice_tx_ring *xdp_ring, struct xdp_desc *de
+ }
+
+ xdp_ring->next_to_use = ntu;
+-
+- if (xdp_ring->next_to_use > xdp_ring->next_rs) {
+- tx_desc = ICE_TX_DESC(xdp_ring, xdp_ring->next_rs);
+- tx_desc->cmd_type_offset_bsz |=
+- cpu_to_le64(ICE_TX_DESC_CMD_RS << ICE_TXD_QW1_CMD_S);
+- xdp_ring->next_rs += tx_thresh;
+- }
+ }
+
+ /**
+@@ -924,7 +896,6 @@ static void ice_xmit_pkt_batch(struct ice_tx_ring *xdp_ring, struct xdp_desc *de
+ static void ice_fill_tx_hw_ring(struct ice_tx_ring *xdp_ring, struct xdp_desc *descs,
+ u32 nb_pkts, unsigned int *total_bytes)
+ {
+- u16 tx_thresh = ICE_RING_QUARTER(xdp_ring);
+ u32 batched, leftover, i;
+
+ batched = ALIGN_DOWN(nb_pkts, PKTS_PER_BATCH);
+@@ -933,54 +904,54 @@ static void ice_fill_tx_hw_ring(struct ice_tx_ring *xdp_ring, struct xdp_desc *d
+ ice_xmit_pkt_batch(xdp_ring, &descs[i], total_bytes);
+ for (; i < batched + leftover; i++)
+ ice_xmit_pkt(xdp_ring, &descs[i], total_bytes);
++}
+
+- if (xdp_ring->next_to_use > xdp_ring->next_rs) {
+- struct ice_tx_desc *tx_desc;
++/**
++ * ice_set_rs_bit - set RS bit on last produced descriptor (one behind current NTU)
++ * @xdp_ring: XDP ring to produce the HW Tx descriptors on
++ */
++static void ice_set_rs_bit(struct ice_tx_ring *xdp_ring)
++{
++ u16 ntu = xdp_ring->next_to_use ? xdp_ring->next_to_use - 1 : xdp_ring->count - 1;
++ struct ice_tx_desc *tx_desc;
+
+- tx_desc = ICE_TX_DESC(xdp_ring, xdp_ring->next_rs);
+- tx_desc->cmd_type_offset_bsz |=
+- cpu_to_le64(ICE_TX_DESC_CMD_RS << ICE_TXD_QW1_CMD_S);
+- xdp_ring->next_rs += tx_thresh;
+- }
++ tx_desc = ICE_TX_DESC(xdp_ring, ntu);
++ tx_desc->cmd_type_offset_bsz |=
++ cpu_to_le64(ICE_TX_DESC_CMD_RS << ICE_TXD_QW1_CMD_S);
+ }
+
+ /**
+ * ice_xmit_zc - take entries from XSK Tx ring and place them onto HW Tx ring
+ * @xdp_ring: XDP ring to produce the HW Tx descriptors on
+- * @budget: number of free descriptors on HW Tx ring that can be used
+- * @napi_budget: amount of descriptors that NAPI allows us to clean
+ *
+ * Returns true if there is no more work that needs to be done, false otherwise
+ */
+-bool ice_xmit_zc(struct ice_tx_ring *xdp_ring, u32 budget, int napi_budget)
++bool ice_xmit_zc(struct ice_tx_ring *xdp_ring)
+ {
+ struct xdp_desc *descs = xdp_ring->xsk_pool->tx_descs;
+- u16 tx_thresh = ICE_RING_QUARTER(xdp_ring);
+ u32 nb_pkts, nb_processed = 0;
+ unsigned int total_bytes = 0;
++ int budget;
++
++ ice_clean_xdp_irq_zc(xdp_ring);
+
+- if (budget < tx_thresh)
+- budget += ice_clean_xdp_irq_zc(xdp_ring, napi_budget);
++ budget = ICE_DESC_UNUSED(xdp_ring);
++ budget = min_t(u16, budget, ICE_RING_QUARTER(xdp_ring));
+
+ nb_pkts = xsk_tx_peek_release_desc_batch(xdp_ring->xsk_pool, budget);
+ if (!nb_pkts)
+ return true;
+
+ if (xdp_ring->next_to_use + nb_pkts >= xdp_ring->count) {
+- struct ice_tx_desc *tx_desc;
+-
+ nb_processed = xdp_ring->count - xdp_ring->next_to_use;
+ ice_fill_tx_hw_ring(xdp_ring, descs, nb_processed, &total_bytes);
+- tx_desc = ICE_TX_DESC(xdp_ring, xdp_ring->next_rs);
+- tx_desc->cmd_type_offset_bsz |=
+- cpu_to_le64(ICE_TX_DESC_CMD_RS << ICE_TXD_QW1_CMD_S);
+- xdp_ring->next_rs = tx_thresh - 1;
+ xdp_ring->next_to_use = 0;
+ }
+
+ ice_fill_tx_hw_ring(xdp_ring, &descs[nb_processed], nb_pkts - nb_processed,
+ &total_bytes);
+
++ ice_set_rs_bit(xdp_ring);
+ ice_xdp_ring_update_tail(xdp_ring);
+ ice_update_tx_ring_stats(xdp_ring, nb_pkts, total_bytes);
+
+@@ -1058,14 +1029,16 @@ bool ice_xsk_any_rx_ring_ena(struct ice_vsi *vsi)
+ */
+ void ice_xsk_clean_rx_ring(struct ice_rx_ring *rx_ring)
+ {
+- u16 count_mask = rx_ring->count - 1;
+ u16 ntc = rx_ring->next_to_clean;
+ u16 ntu = rx_ring->next_to_use;
+
+- for ( ; ntc != ntu; ntc = (ntc + 1) & count_mask) {
++ while (ntc != ntu) {
+ struct xdp_buff *xdp = *ice_xdp_buf(rx_ring, ntc);
+
+ xsk_buff_free(xdp);
++ ntc++;
++ if (ntc >= rx_ring->count)
++ ntc = 0;
+ }
+ }
+
+diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.h b/drivers/net/ethernet/intel/ice/ice_xsk.h
+index 4edbe81eb6460..6fa181f080ef1 100644
+--- a/drivers/net/ethernet/intel/ice/ice_xsk.h
++++ b/drivers/net/ethernet/intel/ice/ice_xsk.h
+@@ -26,13 +26,10 @@ bool ice_alloc_rx_bufs_zc(struct ice_rx_ring *rx_ring, u16 count);
+ bool ice_xsk_any_rx_ring_ena(struct ice_vsi *vsi);
+ void ice_xsk_clean_rx_ring(struct ice_rx_ring *rx_ring);
+ void ice_xsk_clean_xdp_ring(struct ice_tx_ring *xdp_ring);
+-bool ice_xmit_zc(struct ice_tx_ring *xdp_ring, u32 budget, int napi_budget);
++bool ice_xmit_zc(struct ice_tx_ring *xdp_ring);
+ int ice_realloc_zc_buf(struct ice_vsi *vsi, bool zc);
+ #else
+-static inline bool
+-ice_xmit_zc(struct ice_tx_ring __always_unused *xdp_ring,
+- u32 __always_unused budget,
+- int __always_unused napi_budget)
++static inline bool ice_xmit_zc(struct ice_tx_ring __always_unused *xdp_ring)
+ {
+ return false;
+ }
+diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+index 98d6a6d047e32..c1fe1a2cb7460 100644
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -312,8 +312,8 @@
+ #define MTK_RXD5_PPE_CPU_REASON GENMASK(22, 18)
+ #define MTK_RXD5_SRC_PORT GENMASK(29, 26)
+
+-#define RX_DMA_GET_SPORT(x) (((x) >> 19) & 0xf)
+-#define RX_DMA_GET_SPORT_V2(x) (((x) >> 26) & 0x7)
++#define RX_DMA_GET_SPORT(x) (((x) >> 19) & 0x7)
++#define RX_DMA_GET_SPORT_V2(x) (((x) >> 26) & 0xf)
+
+ /* PDMA V2 descriptor rxd3 */
+ #define RX_DMA_VTAG_V2 BIT(0)
+diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c
+index 4aeb927c37153..aa780b1614a3d 100644
+--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c
++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c
+@@ -246,8 +246,8 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv)
+ }
+
+ priv->clk_io = devm_ioremap(dev, res->start, resource_size(res));
+- if (IS_ERR(priv->clk_io))
+- return PTR_ERR(priv->clk_io);
++ if (!priv->clk_io)
++ return -ENOMEM;
+
+ mlxbf_gige_mdio_cfg(priv);
+
+diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
+index 68991b021c560..c250ad6dc956d 100644
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -290,6 +290,13 @@ static int ocelot_port_num_untagged_vlans(struct ocelot *ocelot, int port)
+ if (!(vlan->portmask & BIT(port)))
+ continue;
+
++ /* Ignore the VLAN added by ocelot_add_vlan_unaware_pvid(),
++ * because this is never active in hardware at the same time as
++ * the bridge VLANs, which only matter in VLAN-aware mode.
++ */
++ if (vlan->vid >= OCELOT_RSV_VLAN_RANGE_START)
++ continue;
++
+ if (vlan->untagged & BIT(port))
+ num_untagged++;
+ }
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index 78f11dabca056..8d9272f01e312 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -3704,6 +3704,15 @@ static int stmmac_open(struct net_device *dev)
+ goto init_error;
+ }
+
++ if (priv->plat->serdes_powerup) {
++ ret = priv->plat->serdes_powerup(dev, priv->plat->bsp_priv);
++ if (ret < 0) {
++ netdev_err(priv->dev, "%s: Serdes powerup failed\n",
++ __func__);
++ goto init_error;
++ }
++ }
++
+ ret = stmmac_hw_setup(dev, true);
+ if (ret < 0) {
+ netdev_err(priv->dev, "%s: Hw setup failed\n", __func__);
+@@ -3793,6 +3802,10 @@ static int stmmac_release(struct net_device *dev)
+ /* Disable the MAC Rx/Tx */
+ stmmac_mac_set(priv, priv->ioaddr, false);
+
++ /* Powerdown Serdes if there is */
++ if (priv->plat->serdes_powerdown)
++ priv->plat->serdes_powerdown(dev, priv->plat->bsp_priv);
++
+ netif_carrier_off(dev);
+
+ stmmac_release_ptp(priv);
+@@ -7158,14 +7171,6 @@ int stmmac_dvr_probe(struct device *device,
+ goto error_netdev_register;
+ }
+
+- if (priv->plat->serdes_powerup) {
+- ret = priv->plat->serdes_powerup(ndev,
+- priv->plat->bsp_priv);
+-
+- if (ret < 0)
+- goto error_serdes_powerup;
+- }
+-
+ #ifdef CONFIG_DEBUG_FS
+ stmmac_init_fs(ndev);
+ #endif
+@@ -7180,8 +7185,6 @@ int stmmac_dvr_probe(struct device *device,
+
+ return ret;
+
+-error_serdes_powerup:
+- unregister_netdev(ndev);
+ error_netdev_register:
+ phylink_destroy(priv->phylink);
+ error_xpcs_setup:
+diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
+index f90a21781d8d6..adc9d97cbb88c 100644
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -316,11 +316,13 @@ static __maybe_unused int mdio_bus_phy_resume(struct device *dev)
+
+ phydev->suspended_by_mdio_bus = 0;
+
+- /* If we manged to get here with the PHY state machine in a state neither
+- * PHY_HALTED nor PHY_READY this is an indication that something went wrong
+- * and we should most likely be using MAC managed PM and we are not.
++ /* If we managed to get here with the PHY state machine in a state
++ * neither PHY_HALTED, PHY_READY nor PHY_UP, this is an indication
++ * that something went wrong and we should most likely be using
++ * MAC managed PM, but we are not.
+ */
+- WARN_ON(phydev->state != PHY_HALTED && phydev->state != PHY_READY);
++ WARN_ON(phydev->state != PHY_HALTED && phydev->state != PHY_READY &&
++ phydev->state != PHY_UP);
+
+ ret = phy_init_hw(phydev);
+ if (ret < 0)
+diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
+index 571a399c195dd..c1d4fb62f6dd0 100644
+--- a/drivers/net/usb/qmi_wwan.c
++++ b/drivers/net/usb/qmi_wwan.c
+@@ -1399,6 +1399,7 @@ static const struct usb_device_id products[] = {
+ {QMI_FIXED_INTF(0x413c, 0x81b3, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */
+ {QMI_FIXED_INTF(0x413c, 0x81b6, 8)}, /* Dell Wireless 5811e */
+ {QMI_FIXED_INTF(0x413c, 0x81b6, 10)}, /* Dell Wireless 5811e */
++ {QMI_FIXED_INTF(0x413c, 0x81c2, 8)}, /* Dell Wireless 5811e */
+ {QMI_FIXED_INTF(0x413c, 0x81cc, 8)}, /* Dell Wireless 5816e */
+ {QMI_FIXED_INTF(0x413c, 0x81d7, 0)}, /* Dell Wireless 5821e */
+ {QMI_FIXED_INTF(0x413c, 0x81d7, 1)}, /* Dell Wireless 5821e preproduction config */
+diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
+index 0ed09bb91c442..bccf63aac6cd6 100644
+--- a/drivers/net/usb/usbnet.c
++++ b/drivers/net/usb/usbnet.c
+@@ -1601,6 +1601,7 @@ void usbnet_disconnect (struct usb_interface *intf)
+ struct usbnet *dev;
+ struct usb_device *xdev;
+ struct net_device *net;
++ struct urb *urb;
+
+ dev = usb_get_intfdata(intf);
+ usb_set_intfdata(intf, NULL);
+@@ -1617,7 +1618,11 @@ void usbnet_disconnect (struct usb_interface *intf)
+ net = dev->net;
+ unregister_netdev (net);
+
+- usb_scuttle_anchored_urbs(&dev->deferred);
++ while ((urb = usb_get_from_anchor(&dev->deferred))) {
++ dev_kfree_skb(urb->context);
++ kfree(urb->sg);
++ usb_free_urb(urb);
++ }
+
+ if (dev->driver_info->unbind)
+ dev->driver_info->unbind(dev, intf);
+diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
+index 6d76fc608b741..326ad33537ede 100644
+--- a/drivers/nvme/host/core.c
++++ b/drivers/nvme/host/core.c
+@@ -2069,14 +2069,14 @@ static int nvme_pr_preempt(struct block_device *bdev, u64 old, u64 new,
+
+ static int nvme_pr_clear(struct block_device *bdev, u64 key)
+ {
+- u32 cdw10 = 1 | (key ? 1 << 3 : 0);
++ u32 cdw10 = 1 | (key ? 0 : 1 << 3);
+
+- return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_register);
++ return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_release);
+ }
+
+ static int nvme_pr_release(struct block_device *bdev, u64 key, enum pr_type type)
+ {
+- u32 cdw10 = nvme_pr_type(type) << 8 | (key ? 1 << 3 : 0);
++ u32 cdw10 = nvme_pr_type(type) << 8 | (key ? 0 : 1 << 3);
+
+ return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_release);
+ }
+diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c
+index 185a333df66c5..d2408725eb2c3 100644
+--- a/drivers/reset/reset-imx7.c
++++ b/drivers/reset/reset-imx7.c
+@@ -329,6 +329,7 @@ static int imx8mp_reset_set(struct reset_controller_dev *rcdev,
+ break;
+
+ case IMX8MP_RESET_PCIE_CTRL_APPS_EN:
++ case IMX8MP_RESET_PCIEPHY_PERST:
+ value = assert ? 0 : bit;
+ break;
+ }
+diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
+index a8f3876963a08..09754cd1d57dc 100644
+--- a/drivers/soc/sunxi/sunxi_sram.c
++++ b/drivers/soc/sunxi/sunxi_sram.c
+@@ -78,8 +78,8 @@ static struct sunxi_sram_desc sun4i_a10_sram_d = {
+
+ static struct sunxi_sram_desc sun50i_a64_sram_c = {
+ .data = SUNXI_SRAM_DATA("C", 0x4, 24, 1,
+- SUNXI_SRAM_MAP(0, 1, "cpu"),
+- SUNXI_SRAM_MAP(1, 0, "de2")),
++ SUNXI_SRAM_MAP(1, 0, "cpu"),
++ SUNXI_SRAM_MAP(0, 1, "de2")),
+ };
+
+ static const struct of_device_id sunxi_sram_dt_ids[] = {
+@@ -254,6 +254,7 @@ int sunxi_sram_claim(struct device *dev)
+ writel(val | ((device << sram_data->offset) & mask),
+ base + sram_data->reg);
+
++ sram_desc->claimed = true;
+ spin_unlock(&sram_lock);
+
+ return 0;
+@@ -329,11 +330,11 @@ static struct regmap_config sunxi_sram_emac_clock_regmap = {
+ .writeable_reg = sunxi_sram_regmap_accessible_reg,
+ };
+
+-static int sunxi_sram_probe(struct platform_device *pdev)
++static int __init sunxi_sram_probe(struct platform_device *pdev)
+ {
+- struct dentry *d;
+ struct regmap *emac_clock;
+ const struct sunxi_sramc_variant *variant;
++ struct device *dev = &pdev->dev;
+
+ sram_dev = &pdev->dev;
+
+@@ -345,13 +346,6 @@ static int sunxi_sram_probe(struct platform_device *pdev)
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+- of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+-
+- d = debugfs_create_file("sram", S_IRUGO, NULL, NULL,
+- &sunxi_sram_fops);
+- if (!d)
+- return -ENOMEM;
+-
+ if (variant->num_emac_clocks > 0) {
+ emac_clock = devm_regmap_init_mmio(&pdev->dev, base,
+ &sunxi_sram_emac_clock_regmap);
+@@ -360,6 +354,10 @@ static int sunxi_sram_probe(struct platform_device *pdev)
+ return PTR_ERR(emac_clock);
+ }
+
++ of_platform_populate(dev->of_node, NULL, NULL, dev);
++
++ debugfs_create_file("sram", 0444, NULL, NULL, &sunxi_sram_fops);
++
+ return 0;
+ }
+
+@@ -409,9 +407,8 @@ static struct platform_driver sunxi_sram_driver = {
+ .name = "sunxi-sram",
+ .of_match_table = sunxi_sram_dt_match,
+ },
+- .probe = sunxi_sram_probe,
+ };
+-module_platform_driver(sunxi_sram_driver);
++builtin_platform_driver_probe(sunxi_sram_driver, sunxi_sram_probe);
+
+ MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+ MODULE_DESCRIPTION("Allwinner sunXi SRAM Controller Driver");
+diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
+index 2992fb87cf723..55596ce6bb6e4 100644
+--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
+@@ -1175,8 +1175,8 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
+
+ schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
+
+- writel(0xffffffff, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
+- writel(0xffffffff, rkvdec->regs + RKVDEC_REG_H264_ERR_E);
++ writel(0, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
++ writel(0, rkvdec->regs + RKVDEC_REG_H264_ERR_E);
+ writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
+ writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
+
+diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
+index 64f0aec7e70ae..0508da6f63d9e 100644
+--- a/drivers/thunderbolt/switch.c
++++ b/drivers/thunderbolt/switch.c
+@@ -2413,6 +2413,7 @@ int tb_switch_configure(struct tb_switch *sw)
+ * additional capabilities.
+ */
+ sw->config.cmuv = USB4_VERSION_1_0;
++ sw->config.plug_events_delay = 0xa;
+
+ /* Enumerate the switch */
+ ret = tb_sw_write(sw, (u32 *)&sw->config + 1, TB_CFG_SWITCH,
+diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h
+index 23ab3b048d9be..251778d14e2dd 100644
+--- a/drivers/usb/storage/unusual_uas.h
++++ b/drivers/usb/storage/unusual_uas.h
+@@ -52,6 +52,13 @@ UNUSUAL_DEV(0x059f, 0x1061, 0x0000, 0x9999,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_NO_REPORT_OPCODES | US_FL_NO_SAME),
+
++/* Reported-by: Hongling Zeng <zenghongling@kylinos.cn> */
++UNUSUAL_DEV(0x090c, 0x2000, 0x0000, 0x9999,
++ "Hiksemi",
++ "External HDD",
++ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
++ US_FL_IGNORE_UAS),
++
+ /*
+ * Apricorn USB3 dongle sometimes returns "USBSUSBSUSBS" in response to SCSI
+ * commands in UAS mode. Observed with the 1.28 firmware; are there others?
+@@ -76,6 +83,13 @@ UNUSUAL_DEV(0x0bc2, 0x331a, 0x0000, 0x9999,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_NO_REPORT_LUNS),
+
++/* Reported-by: Hongling Zeng <zenghongling@kylinos.cn> */
++UNUSUAL_DEV(0x0bda, 0x9210, 0x0000, 0x9999,
++ "Hiksemi",
++ "External HDD",
++ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
++ US_FL_IGNORE_UAS),
++
+ /* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */
+ UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999,
+ "Initio Corporation",
+@@ -118,6 +132,13 @@ UNUSUAL_DEV(0x154b, 0xf00d, 0x0000, 0x9999,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_NO_ATA_1X),
+
++/* Reported-by: Hongling Zeng <zenghongling@kylinos.cn> */
++UNUSUAL_DEV(0x17ef, 0x3899, 0x0000, 0x9999,
++ "Thinkplus",
++ "External HDD",
++ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
++ US_FL_IGNORE_UAS),
++
+ /* Reported-by: Hans de Goede <hdegoede@redhat.com> */
+ UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999,
+ "VIA",
+diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
+index 7f2624f427241..6364f0d467ea3 100644
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -588,8 +588,6 @@ static int ucsi_get_pdos(struct ucsi_connector *con, int is_partner,
+ num_pdos * sizeof(u32));
+ if (ret < 0 && ret != -ETIMEDOUT)
+ dev_err(ucsi->dev, "UCSI_GET_PDOS failed (%d)\n", ret);
+- if (ret == 0 && offset == 0)
+- dev_warn(ucsi->dev, "UCSI_GET_PDOS returned 0 bytes\n");
+
+ return ret;
+ }
+diff --git a/drivers/vdpa/ifcvf/ifcvf_base.c b/drivers/vdpa/ifcvf/ifcvf_base.c
+index 48c4dadb0c7c7..a4c1b985f79a7 100644
+--- a/drivers/vdpa/ifcvf/ifcvf_base.c
++++ b/drivers/vdpa/ifcvf/ifcvf_base.c
+@@ -315,7 +315,7 @@ u16 ifcvf_get_vq_state(struct ifcvf_hw *hw, u16 qid)
+ u32 q_pair_id;
+
+ ifcvf_lm = (struct ifcvf_lm_cfg __iomem *)hw->lm_cfg;
+- q_pair_id = qid / hw->nr_vring;
++ q_pair_id = qid / 2;
+ avail_idx_addr = &ifcvf_lm->vring_lm_cfg[q_pair_id].idx_addr[qid % 2];
+ last_avail_idx = vp_ioread16(avail_idx_addr);
+
+@@ -329,7 +329,7 @@ int ifcvf_set_vq_state(struct ifcvf_hw *hw, u16 qid, u16 num)
+ u32 q_pair_id;
+
+ ifcvf_lm = (struct ifcvf_lm_cfg __iomem *)hw->lm_cfg;
+- q_pair_id = qid / hw->nr_vring;
++ q_pair_id = qid / 2;
+ avail_idx_addr = &ifcvf_lm->vring_lm_cfg[q_pair_id].idx_addr[qid % 2];
+ hw->vring[qid].last_avail_idx = num;
+ vp_iowrite16(num, avail_idx_addr);
+diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c
+index e85c1d71f4ed2..f527cbeb11699 100644
+--- a/drivers/vdpa/mlx5/net/mlx5_vnet.c
++++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c
+@@ -1297,6 +1297,8 @@ static void teardown_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *
+
+ static int create_rqt(struct mlx5_vdpa_net *ndev)
+ {
++ int rqt_table_size = roundup_pow_of_two(ndev->rqt_size);
++ int act_sz = roundup_pow_of_two(ndev->cur_num_vqs / 2);
+ __be32 *list;
+ void *rqtc;
+ int inlen;
+@@ -1304,7 +1306,7 @@ static int create_rqt(struct mlx5_vdpa_net *ndev)
+ int i, j;
+ int err;
+
+- inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + ndev->rqt_size * MLX5_ST_SZ_BYTES(rq_num);
++ inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + rqt_table_size * MLX5_ST_SZ_BYTES(rq_num);
+ in = kzalloc(inlen, GFP_KERNEL);
+ if (!in)
+ return -ENOMEM;
+@@ -1313,12 +1315,12 @@ static int create_rqt(struct mlx5_vdpa_net *ndev)
+ rqtc = MLX5_ADDR_OF(create_rqt_in, in, rqt_context);
+
+ MLX5_SET(rqtc, rqtc, list_q_type, MLX5_RQTC_LIST_Q_TYPE_VIRTIO_NET_Q);
+- MLX5_SET(rqtc, rqtc, rqt_max_size, ndev->rqt_size);
++ MLX5_SET(rqtc, rqtc, rqt_max_size, rqt_table_size);
+ list = MLX5_ADDR_OF(rqtc, rqtc, rq_num[0]);
+- for (i = 0, j = 0; i < ndev->rqt_size; i++, j += 2)
++ for (i = 0, j = 0; i < act_sz; i++, j += 2)
+ list[i] = cpu_to_be32(ndev->vqs[j % ndev->cur_num_vqs].virtq_id);
+
+- MLX5_SET(rqtc, rqtc, rqt_actual_size, ndev->rqt_size);
++ MLX5_SET(rqtc, rqtc, rqt_actual_size, act_sz);
+ err = mlx5_vdpa_create_rqt(&ndev->mvdev, in, inlen, &ndev->res.rqtn);
+ kfree(in);
+ if (err)
+@@ -1331,6 +1333,7 @@ static int create_rqt(struct mlx5_vdpa_net *ndev)
+
+ static int modify_rqt(struct mlx5_vdpa_net *ndev, int num)
+ {
++ int act_sz = roundup_pow_of_two(num / 2);
+ __be32 *list;
+ void *rqtc;
+ int inlen;
+@@ -1338,7 +1341,7 @@ static int modify_rqt(struct mlx5_vdpa_net *ndev, int num)
+ int i, j;
+ int err;
+
+- inlen = MLX5_ST_SZ_BYTES(modify_rqt_in) + ndev->rqt_size * MLX5_ST_SZ_BYTES(rq_num);
++ inlen = MLX5_ST_SZ_BYTES(modify_rqt_in) + act_sz * MLX5_ST_SZ_BYTES(rq_num);
+ in = kzalloc(inlen, GFP_KERNEL);
+ if (!in)
+ return -ENOMEM;
+@@ -1349,10 +1352,10 @@ static int modify_rqt(struct mlx5_vdpa_net *ndev, int num)
+ MLX5_SET(rqtc, rqtc, list_q_type, MLX5_RQTC_LIST_Q_TYPE_VIRTIO_NET_Q);
+
+ list = MLX5_ADDR_OF(rqtc, rqtc, rq_num[0]);
+- for (i = 0, j = 0; i < ndev->rqt_size; i++, j += 2)
++ for (i = 0, j = 0; i < act_sz; i++, j = j + 2)
+ list[i] = cpu_to_be32(ndev->vqs[j % num].virtq_id);
+
+- MLX5_SET(rqtc, rqtc, rqt_actual_size, ndev->rqt_size);
++ MLX5_SET(rqtc, rqtc, rqt_actual_size, act_sz);
+ err = mlx5_vdpa_modify_rqt(&ndev->mvdev, in, inlen, ndev->res.rqtn);
+ kfree(in);
+ if (err)
+diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c
+index 3bc27de58f46b..8e0efae6cc8ad 100644
+--- a/drivers/vdpa/vdpa_user/vduse_dev.c
++++ b/drivers/vdpa/vdpa_user/vduse_dev.c
+@@ -662,10 +662,15 @@ static void vduse_vdpa_get_config(struct vdpa_device *vdpa, unsigned int offset,
+ {
+ struct vduse_dev *dev = vdpa_to_vduse(vdpa);
+
+- if (offset > dev->config_size ||
+- len > dev->config_size - offset)
++ /* Initialize the buffer in case of partial copy. */
++ memset(buf, 0, len);
++
++ if (offset > dev->config_size)
+ return;
+
++ if (len > dev->config_size - offset)
++ len = dev->config_size - offset;
++
+ memcpy(buf, dev->config + offset, len);
+ }
+
+diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
+index 5ae8de09b271b..001f4e053c85a 100644
+--- a/fs/ntfs/super.c
++++ b/fs/ntfs/super.c
+@@ -2092,7 +2092,8 @@ get_ctx_vol_failed:
+ // TODO: Initialize security.
+ /* Get the extended system files' directory inode. */
+ vol->extend_ino = ntfs_iget(sb, FILE_Extend);
+- if (IS_ERR(vol->extend_ino) || is_bad_inode(vol->extend_ino)) {
++ if (IS_ERR(vol->extend_ino) || is_bad_inode(vol->extend_ino) ||
++ !S_ISDIR(vol->extend_ino->i_mode)) {
+ if (!IS_ERR(vol->extend_ino))
+ iput(vol->extend_ino);
+ ntfs_error(sb, "Failed to load $Extend.");
+diff --git a/mm/damon/dbgfs.c b/mm/damon/dbgfs.c
+index 53ba8b1e619ca..89075fa4e8a9a 100644
+--- a/mm/damon/dbgfs.c
++++ b/mm/damon/dbgfs.c
+@@ -853,6 +853,7 @@ static int dbgfs_rm_context(char *name)
+ struct dentry *root, *dir, **new_dirs;
+ struct damon_ctx **new_ctxs;
+ int i, j;
++ int ret = 0;
+
+ if (damon_nr_running_ctxs())
+ return -EBUSY;
+@@ -867,14 +868,16 @@ static int dbgfs_rm_context(char *name)
+
+ new_dirs = kmalloc_array(dbgfs_nr_ctxs - 1, sizeof(*dbgfs_dirs),
+ GFP_KERNEL);
+- if (!new_dirs)
+- return -ENOMEM;
++ if (!new_dirs) {
++ ret = -ENOMEM;
++ goto out_dput;
++ }
+
+ new_ctxs = kmalloc_array(dbgfs_nr_ctxs - 1, sizeof(*dbgfs_ctxs),
+ GFP_KERNEL);
+ if (!new_ctxs) {
+- kfree(new_dirs);
+- return -ENOMEM;
++ ret = -ENOMEM;
++ goto out_new_dirs;
+ }
+
+ for (i = 0, j = 0; i < dbgfs_nr_ctxs; i++) {
+@@ -894,7 +897,13 @@ static int dbgfs_rm_context(char *name)
+ dbgfs_ctxs = new_ctxs;
+ dbgfs_nr_ctxs--;
+
+- return 0;
++ goto out_dput;
++
++out_new_dirs:
++ kfree(new_dirs);
++out_dput:
++ dput(dir);
++ return ret;
+ }
+
+ static ssize_t dbgfs_rm_context_write(struct file *file,
+diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
+index 09f9e8ca3d1fa..5b5ee3308d71b 100644
+--- a/mm/damon/sysfs.c
++++ b/mm/damon/sysfs.c
+@@ -2181,13 +2181,13 @@ static int damon_sysfs_add_target(struct damon_sysfs_target *sys_target,
+
+ if (!t)
+ return -ENOMEM;
++ damon_add_target(ctx, t);
+ if (ctx->ops.id == DAMON_OPS_VADDR ||
+ ctx->ops.id == DAMON_OPS_FVADDR) {
+ t->pid = find_get_pid(sys_target->pid);
+ if (!t->pid)
+ goto destroy_targets_out;
+ }
+- damon_add_target(ctx, t);
+ err = damon_sysfs_set_regions(t, sys_target->regions);
+ if (err)
+ goto destroy_targets_out;
+diff --git a/mm/frontswap.c b/mm/frontswap.c
+index 6f69b044a8cc7..42262cb6a8646 100644
+--- a/mm/frontswap.c
++++ b/mm/frontswap.c
+@@ -125,6 +125,9 @@ void frontswap_init(unsigned type, unsigned long *map)
+ * p->frontswap set to something valid to work properly.
+ */
+ frontswap_map_set(sis, map);
++
++ if (!frontswap_enabled())
++ return;
+ frontswap_ops->init(type);
+ }
+
+diff --git a/mm/gup.c b/mm/gup.c
+index 38effce68b48d..0d500cdfa6e0e 100644
+--- a/mm/gup.c
++++ b/mm/gup.c
+@@ -2278,8 +2278,28 @@ static void __maybe_unused undo_dev_pagemap(int *nr, int nr_start,
+ }
+
+ #ifdef CONFIG_ARCH_HAS_PTE_SPECIAL
+-static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end,
+- unsigned int flags, struct page **pages, int *nr)
++/*
++ * Fast-gup relies on pte change detection to avoid concurrent pgtable
++ * operations.
++ *
++ * To pin the page, fast-gup needs to do below in order:
++ * (1) pin the page (by prefetching pte), then (2) check pte not changed.
++ *
++ * For the rest of pgtable operations where pgtable updates can be racy
++ * with fast-gup, we need to do (1) clear pte, then (2) check whether page
++ * is pinned.
++ *
++ * Above will work for all pte-level operations, including THP split.
++ *
++ * For THP collapse, it's a bit more complicated because fast-gup may be
++ * walking a pgtable page that is being freed (pte is still valid but pmd
++ * can be cleared already). To avoid race in such condition, we need to
++ * also check pmd here to make sure pmd doesn't change (corresponds to
++ * pmdp_collapse_flush() in the THP collapse code path).
++ */
++static int gup_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr,
++ unsigned long end, unsigned int flags,
++ struct page **pages, int *nr)
+ {
+ struct dev_pagemap *pgmap = NULL;
+ int nr_start = *nr, ret = 0;
+@@ -2325,7 +2345,8 @@ static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end,
+ goto pte_unmap;
+ }
+
+- if (unlikely(pte_val(pte) != pte_val(*ptep))) {
++ if (unlikely(pmd_val(pmd) != pmd_val(*pmdp)) ||
++ unlikely(pte_val(pte) != pte_val(*ptep))) {
+ gup_put_folio(folio, 1, flags);
+ goto pte_unmap;
+ }
+@@ -2372,8 +2393,9 @@ pte_unmap:
+ * get_user_pages_fast_only implementation that can pin pages. Thus it's still
+ * useful to have gup_huge_pmd even if we can't operate on ptes.
+ */
+-static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end,
+- unsigned int flags, struct page **pages, int *nr)
++static int gup_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr,
++ unsigned long end, unsigned int flags,
++ struct page **pages, int *nr)
+ {
+ return 0;
+ }
+@@ -2697,7 +2719,7 @@ static int gup_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr, unsigned lo
+ if (!gup_huge_pd(__hugepd(pmd_val(pmd)), addr,
+ PMD_SHIFT, next, flags, pages, nr))
+ return 0;
+- } else if (!gup_pte_range(pmd, addr, next, flags, pages, nr))
++ } else if (!gup_pte_range(pmd, pmdp, addr, next, flags, pages, nr))
+ return 0;
+ } while (pmdp++, addr = next, addr != end);
+
+diff --git a/mm/hugetlb.c b/mm/hugetlb.c
+index 299dcfaa35b25..b508efbdcdbed 100644
+--- a/mm/hugetlb.c
++++ b/mm/hugetlb.c
+@@ -3418,6 +3418,7 @@ static int demote_free_huge_page(struct hstate *h, struct page *page)
+ {
+ int i, nid = page_to_nid(page);
+ struct hstate *target_hstate;
++ struct page *subpage;
+ int rc = 0;
+
+ target_hstate = size_to_hstate(PAGE_SIZE << h->demote_order);
+@@ -3451,15 +3452,16 @@ static int demote_free_huge_page(struct hstate *h, struct page *page)
+ mutex_lock(&target_hstate->resize_lock);
+ for (i = 0; i < pages_per_huge_page(h);
+ i += pages_per_huge_page(target_hstate)) {
++ subpage = nth_page(page, i);
+ if (hstate_is_gigantic(target_hstate))
+- prep_compound_gigantic_page_for_demote(page + i,
++ prep_compound_gigantic_page_for_demote(subpage,
+ target_hstate->order);
+ else
+- prep_compound_page(page + i, target_hstate->order);
+- set_page_private(page + i, 0);
+- set_page_refcounted(page + i);
+- prep_new_huge_page(target_hstate, page + i, nid);
+- put_page(page + i);
++ prep_compound_page(subpage, target_hstate->order);
++ set_page_private(subpage, 0);
++ set_page_refcounted(subpage);
++ prep_new_huge_page(target_hstate, subpage, nid);
++ put_page(subpage);
+ }
+ mutex_unlock(&target_hstate->resize_lock);
+
+diff --git a/mm/khugepaged.c b/mm/khugepaged.c
+index 16be62d493cd9..6c16db25ff8e3 100644
+--- a/mm/khugepaged.c
++++ b/mm/khugepaged.c
+@@ -1121,10 +1121,12 @@ static void collapse_huge_page(struct mm_struct *mm,
+
+ pmd_ptl = pmd_lock(mm, pmd); /* probably unnecessary */
+ /*
+- * After this gup_fast can't run anymore. This also removes
+- * any huge TLB entry from the CPU so we won't allow
+- * huge and small TLB entries for the same virtual address
+- * to avoid the risk of CPU bugs in that area.
++ * This removes any huge TLB entry from the CPU so we won't allow
++ * huge and small TLB entries for the same virtual address to
++ * avoid the risk of CPU bugs in that area.
++ *
++ * Parallel fast GUP is fine since fast GUP will back off when
++ * it detects PMD is changed.
+ */
+ _pmd = pmdp_collapse_flush(vma, address, pmd);
+ spin_unlock(pmd_ptl);
+diff --git a/mm/madvise.c b/mm/madvise.c
+index 0316bbc6441b2..bb4a714fea5e7 100644
+--- a/mm/madvise.c
++++ b/mm/madvise.c
+@@ -451,8 +451,11 @@ regular_page:
+ continue;
+ }
+
+- /* Do not interfere with other mappings of this page */
+- if (page_mapcount(page) != 1)
++ /*
++ * Do not interfere with other mappings of this page and
++ * non-LRU page.
++ */
++ if (!PageLRU(page) || page_mapcount(page) != 1)
+ continue;
+
+ VM_BUG_ON_PAGE(PageTransCompound(page), page);
+diff --git a/mm/memory-failure.c b/mm/memory-failure.c
+index 845369f839e19..828801eab6aca 100644
+--- a/mm/memory-failure.c
++++ b/mm/memory-failure.c
+@@ -697,6 +697,9 @@ static int kill_accessing_process(struct task_struct *p, unsigned long pfn,
+ };
+ priv.tk.tsk = p;
+
++ if (!p->mm)
++ return -EFAULT;
++
+ mmap_read_lock(p->mm);
+ ret = walk_page_range(p->mm, 0, TASK_SIZE, &hwp_walk_ops,
+ (void *)&priv);
+diff --git a/mm/memory.c b/mm/memory.c
+index 1c6027adc5426..e644f6fad3892 100644
+--- a/mm/memory.c
++++ b/mm/memory.c
+@@ -4378,14 +4378,20 @@ vm_fault_t finish_fault(struct vm_fault *vmf)
+
+ vmf->pte = pte_offset_map_lock(vma->vm_mm, vmf->pmd,
+ vmf->address, &vmf->ptl);
+- ret = 0;
++
+ /* Re-check under ptl */
+- if (likely(!vmf_pte_changed(vmf)))
++ if (likely(!vmf_pte_changed(vmf))) {
+ do_set_pte(vmf, page, vmf->address);
+- else
++
++ /* no need to invalidate: a not-present page won't be cached */
++ update_mmu_cache(vma, vmf->address, vmf->pte);
++
++ ret = 0;
++ } else {
++ update_mmu_tlb(vma, vmf->address, vmf->pte);
+ ret = VM_FAULT_NOPAGE;
++ }
+
+- update_mmu_tlb(vma, vmf->address, vmf->pte);
+ pte_unmap_unlock(vmf->pte, vmf->ptl);
+ return ret;
+ }
+diff --git a/mm/migrate_device.c b/mm/migrate_device.c
+index 5052093d0262d..0370f23c3b01f 100644
+--- a/mm/migrate_device.c
++++ b/mm/migrate_device.c
+@@ -7,6 +7,7 @@
+ #include <linux/export.h>
+ #include <linux/memremap.h>
+ #include <linux/migrate.h>
++#include <linux/mm.h>
+ #include <linux/mm_inline.h>
+ #include <linux/mmu_notifier.h>
+ #include <linux/oom.h>
+@@ -187,10 +188,10 @@ again:
+ bool anon_exclusive;
+ pte_t swp_pte;
+
++ flush_cache_page(vma, addr, pte_pfn(*ptep));
+ anon_exclusive = PageAnon(page) && PageAnonExclusive(page);
+ if (anon_exclusive) {
+- flush_cache_page(vma, addr, pte_pfn(*ptep));
+- ptep_clear_flush(vma, addr, ptep);
++ pte = ptep_clear_flush(vma, addr, ptep);
+
+ if (page_try_share_anon_rmap(page)) {
+ set_pte_at(mm, addr, ptep, pte);
+@@ -200,11 +201,15 @@ again:
+ goto next;
+ }
+ } else {
+- ptep_get_and_clear(mm, addr, ptep);
++ pte = ptep_get_and_clear(mm, addr, ptep);
+ }
+
+ migrate->cpages++;
+
++ /* Set the dirty flag on the folio now the pte is gone. */
++ if (pte_dirty(pte))
++ folio_mark_dirty(page_folio(page));
++
+ /* Setup special migration page table entry */
+ if (mpfn & MIGRATE_PFN_WRITE)
+ entry = make_writable_migration_entry(
+@@ -248,13 +253,14 @@ next:
+ migrate->dst[migrate->npages] = 0;
+ migrate->src[migrate->npages++] = mpfn;
+ }
+- arch_leave_lazy_mmu_mode();
+- pte_unmap_unlock(ptep - 1, ptl);
+
+ /* Only flush the TLB if we actually modified any entries */
+ if (unmapped)
+ flush_tlb_range(walk->vma, start, end);
+
++ arch_leave_lazy_mmu_mode();
++ pte_unmap_unlock(ptep - 1, ptl);
++
+ return 0;
+ }
+
+diff --git a/mm/page_alloc.c b/mm/page_alloc.c
+index cdf0e7d707c37..a88d06dac743e 100644
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -4623,6 +4623,30 @@ void fs_reclaim_release(gfp_t gfp_mask)
+ EXPORT_SYMBOL_GPL(fs_reclaim_release);
+ #endif
+
++/*
++ * Zonelists may change due to hotplug during allocation. Detect when zonelists
++ * have been rebuilt so allocation retries. Reader side does not lock and
++ * retries the allocation if zonelist changes. Writer side is protected by the
++ * embedded spin_lock.
++ */
++static DEFINE_SEQLOCK(zonelist_update_seq);
++
++static unsigned int zonelist_iter_begin(void)
++{
++ if (IS_ENABLED(CONFIG_MEMORY_HOTREMOVE))
++ return read_seqbegin(&zonelist_update_seq);
++
++ return 0;
++}
++
++static unsigned int check_retry_zonelist(unsigned int seq)
++{
++ if (IS_ENABLED(CONFIG_MEMORY_HOTREMOVE))
++ return read_seqretry(&zonelist_update_seq, seq);
++
++ return seq;
++}
++
+ /* Perform direct synchronous page reclaim */
+ static unsigned long
+ __perform_reclaim(gfp_t gfp_mask, unsigned int order,
+@@ -4916,6 +4940,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
+ int compaction_retries;
+ int no_progress_loops;
+ unsigned int cpuset_mems_cookie;
++ unsigned int zonelist_iter_cookie;
+ int reserve_flags;
+
+ /*
+@@ -4926,11 +4951,12 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
+ (__GFP_ATOMIC|__GFP_DIRECT_RECLAIM)))
+ gfp_mask &= ~__GFP_ATOMIC;
+
+-retry_cpuset:
++restart:
+ compaction_retries = 0;
+ no_progress_loops = 0;
+ compact_priority = DEF_COMPACT_PRIORITY;
+ cpuset_mems_cookie = read_mems_allowed_begin();
++ zonelist_iter_cookie = zonelist_iter_begin();
+
+ /*
+ * The fast path uses conservative alloc_flags to succeed only until
+@@ -5102,9 +5128,13 @@ retry:
+ goto retry;
+
+
+- /* Deal with possible cpuset update races before we start OOM killing */
+- if (check_retry_cpuset(cpuset_mems_cookie, ac))
+- goto retry_cpuset;
++ /*
++ * Deal with possible cpuset update races or zonelist updates to avoid
++ * a unnecessary OOM kill.
++ */
++ if (check_retry_cpuset(cpuset_mems_cookie, ac) ||
++ check_retry_zonelist(zonelist_iter_cookie))
++ goto restart;
+
+ /* Reclaim has failed us, start killing things */
+ page = __alloc_pages_may_oom(gfp_mask, order, ac, &did_some_progress);
+@@ -5124,9 +5154,13 @@ retry:
+ }
+
+ nopage:
+- /* Deal with possible cpuset update races before we fail */
+- if (check_retry_cpuset(cpuset_mems_cookie, ac))
+- goto retry_cpuset;
++ /*
++ * Deal with possible cpuset update races or zonelist updates to avoid
++ * a unnecessary OOM kill.
++ */
++ if (check_retry_cpuset(cpuset_mems_cookie, ac) ||
++ check_retry_zonelist(zonelist_iter_cookie))
++ goto restart;
+
+ /*
+ * Make sure that __GFP_NOFAIL request doesn't leak out and make sure
+@@ -5617,6 +5651,18 @@ refill:
+ /* reset page count bias and offset to start of new frag */
+ nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1;
+ offset = size - fragsz;
++ if (unlikely(offset < 0)) {
++ /*
++ * The caller is trying to allocate a fragment
++ * with fragsz > PAGE_SIZE but the cache isn't big
++ * enough to satisfy the request, this may
++ * happen in low memory conditions.
++ * We don't release the cache page because
++ * it could make memory pressure worse
++ * so we simply return NULL here.
++ */
++ return NULL;
++ }
+ }
+
+ nc->pagecnt_bias--;
+@@ -6421,9 +6467,8 @@ static void __build_all_zonelists(void *data)
+ int nid;
+ int __maybe_unused cpu;
+ pg_data_t *self = data;
+- static DEFINE_SPINLOCK(lock);
+
+- spin_lock(&lock);
++ write_seqlock(&zonelist_update_seq);
+
+ #ifdef CONFIG_NUMA
+ memset(node_load, 0, sizeof(node_load));
+@@ -6460,7 +6505,7 @@ static void __build_all_zonelists(void *data)
+ #endif
+ }
+
+- spin_unlock(&lock);
++ write_sequnlock(&zonelist_update_seq);
+ }
+
+ static noinline void __init
+diff --git a/mm/page_isolation.c b/mm/page_isolation.c
+index 9d73dc38e3d75..eb3a68ca92ad9 100644
+--- a/mm/page_isolation.c
++++ b/mm/page_isolation.c
+@@ -288,6 +288,7 @@ __first_valid_page(unsigned long pfn, unsigned long nr_pages)
+ * @isolate_before: isolate the pageblock before the boundary_pfn
+ * @skip_isolation: the flag to skip the pageblock isolation in second
+ * isolate_single_pageblock()
++ * @migratetype: migrate type to set in error recovery.
+ *
+ * Free and in-use pages can be as big as MAX_ORDER-1 and contain more than one
+ * pageblock. When not all pageblocks within a page are isolated at the same
+@@ -302,9 +303,9 @@ __first_valid_page(unsigned long pfn, unsigned long nr_pages)
+ * the in-use page then splitting the free page.
+ */
+ static int isolate_single_pageblock(unsigned long boundary_pfn, int flags,
+- gfp_t gfp_flags, bool isolate_before, bool skip_isolation)
++ gfp_t gfp_flags, bool isolate_before, bool skip_isolation,
++ int migratetype)
+ {
+- unsigned char saved_mt;
+ unsigned long start_pfn;
+ unsigned long isolate_pageblock;
+ unsigned long pfn;
+@@ -328,13 +329,13 @@ static int isolate_single_pageblock(unsigned long boundary_pfn, int flags,
+ start_pfn = max(ALIGN_DOWN(isolate_pageblock, MAX_ORDER_NR_PAGES),
+ zone->zone_start_pfn);
+
+- saved_mt = get_pageblock_migratetype(pfn_to_page(isolate_pageblock));
++ if (skip_isolation) {
++ int mt = get_pageblock_migratetype(pfn_to_page(isolate_pageblock));
+
+- if (skip_isolation)
+- VM_BUG_ON(!is_migrate_isolate(saved_mt));
+- else {
+- ret = set_migratetype_isolate(pfn_to_page(isolate_pageblock), saved_mt, flags,
+- isolate_pageblock, isolate_pageblock + pageblock_nr_pages);
++ VM_BUG_ON(!is_migrate_isolate(mt));
++ } else {
++ ret = set_migratetype_isolate(pfn_to_page(isolate_pageblock), migratetype,
++ flags, isolate_pageblock, isolate_pageblock + pageblock_nr_pages);
+
+ if (ret)
+ return ret;
+@@ -475,7 +476,7 @@ static int isolate_single_pageblock(unsigned long boundary_pfn, int flags,
+ failed:
+ /* restore the original migratetype */
+ if (!skip_isolation)
+- unset_migratetype_isolate(pfn_to_page(isolate_pageblock), saved_mt);
++ unset_migratetype_isolate(pfn_to_page(isolate_pageblock), migratetype);
+ return -EBUSY;
+ }
+
+@@ -537,7 +538,8 @@ int start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
+ bool skip_isolation = false;
+
+ /* isolate [isolate_start, isolate_start + pageblock_nr_pages) pageblock */
+- ret = isolate_single_pageblock(isolate_start, flags, gfp_flags, false, skip_isolation);
++ ret = isolate_single_pageblock(isolate_start, flags, gfp_flags, false,
++ skip_isolation, migratetype);
+ if (ret)
+ return ret;
+
+@@ -545,7 +547,8 @@ int start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
+ skip_isolation = true;
+
+ /* isolate [isolate_end - pageblock_nr_pages, isolate_end) pageblock */
+- ret = isolate_single_pageblock(isolate_end, flags, gfp_flags, true, skip_isolation);
++ ret = isolate_single_pageblock(isolate_end, flags, gfp_flags, true,
++ skip_isolation, migratetype);
+ if (ret) {
+ unset_migratetype_isolate(pfn_to_page(isolate_start), migratetype);
+ return ret;
+diff --git a/mm/secretmem.c b/mm/secretmem.c
+index f06279d6190a5..53f3badce7e4a 100644
+--- a/mm/secretmem.c
++++ b/mm/secretmem.c
+@@ -283,7 +283,7 @@ static int secretmem_init(void)
+
+ secretmem_mnt = kern_mount(&secretmem_fs);
+ if (IS_ERR(secretmem_mnt))
+- ret = PTR_ERR(secretmem_mnt);
++ return PTR_ERR(secretmem_mnt);
+
+ /* prevent secretmem mappings from ever getting PROT_EXEC */
+ secretmem_mnt->mnt_flags |= MNT_NOEXEC;
+diff --git a/mm/util.c b/mm/util.c
+index 0837570c92251..95d8472747f99 100644
+--- a/mm/util.c
++++ b/mm/util.c
+@@ -619,6 +619,10 @@ void *kvmalloc_node(size_t size, gfp_t flags, int node)
+ if (ret || size <= PAGE_SIZE)
+ return ret;
+
++ /* non-sleeping allocations are not supported by vmalloc */
++ if (!gfpflags_allow_blocking(flags))
++ return NULL;
++
+ /* Don't even allow crazy sizes */
+ if (unlikely(size > INT_MAX)) {
+ WARN_ON_ONCE(!(flags & __GFP_NOWARN));
+diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
+index 5f27e6746762a..788a82f9c74d5 100644
+--- a/net/mac80211/rc80211_minstrel_ht.c
++++ b/net/mac80211/rc80211_minstrel_ht.c
+@@ -10,6 +10,7 @@
+ #include <linux/random.h>
+ #include <linux/moduleparam.h>
+ #include <linux/ieee80211.h>
++#include <linux/minmax.h>
+ #include <net/mac80211.h>
+ #include "rate.h"
+ #include "sta_info.h"
+@@ -1550,6 +1551,7 @@ minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
+ {
+ struct ieee80211_sta_rates *rates;
+ int i = 0;
++ int max_rates = min_t(int, mp->hw->max_rates, IEEE80211_TX_RATE_TABLE_SIZE);
+
+ rates = kzalloc(sizeof(*rates), GFP_ATOMIC);
+ if (!rates)
+@@ -1559,10 +1561,10 @@ minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
+ minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate[0]);
+
+ /* Fill up remaining, keep one entry for max_probe_rate */
+- for (; i < (mp->hw->max_rates - 1); i++)
++ for (; i < (max_rates - 1); i++)
+ minstrel_ht_set_rate(mp, mi, rates, i, mi->max_tp_rate[i]);
+
+- if (i < mp->hw->max_rates)
++ if (i < max_rates)
+ minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_prob_rate);
+
+ if (i < IEEE80211_TX_RATE_TABLE_SIZE)
+diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
+index 3cd24d8170d32..f6f09a3506aae 100644
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -5761,6 +5761,9 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
+ skb_reset_network_header(skb);
+ skb_reset_mac_header(skb);
+
++ if (local->hw.queues < IEEE80211_NUM_ACS)
++ goto start_xmit;
++
+ /* update QoS header to prioritize control port frames if possible,
+ * priorization also happens for control port frames send over
+ * AF_PACKET
+@@ -5776,6 +5779,7 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
+
+ rcu_read_unlock();
+
++start_xmit:
+ /* mutex lock is only needed for incrementing the cookie counter */
+ mutex_lock(&local->mtx);
+
+diff --git a/net/mac80211/util.c b/net/mac80211/util.c
+index b58df3e63a86a..3f698e508dd71 100644
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -301,14 +301,14 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
+ local_bh_disable();
+ spin_lock(&fq->lock);
+
++ sdata->vif.txqs_stopped[ac] = false;
++
+ if (!test_bit(SDATA_STATE_RUNNING, &sdata->state))
+ goto out;
+
+ if (sdata->vif.type == NL80211_IFTYPE_AP)
+ ps = &sdata->bss->ps;
+
+- sdata->vif.txqs_stopped[ac] = false;
+-
+ list_for_each_entry_rcu(sta, &local->sta_list, list) {
+ if (sdata != sta->sdata)
+ continue;
+diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
+index 513f571a082ba..e44b5ea1a448b 100644
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -2692,7 +2692,7 @@ static void __mptcp_clear_xmit(struct sock *sk)
+ dfrag_clear(sk, dfrag);
+ }
+
+-static void mptcp_cancel_work(struct sock *sk)
++void mptcp_cancel_work(struct sock *sk)
+ {
+ struct mptcp_sock *msk = mptcp_sk(sk);
+
+@@ -2832,13 +2832,12 @@ static void __mptcp_destroy_sock(struct sock *sk)
+ sock_put(sk);
+ }
+
+-static void mptcp_close(struct sock *sk, long timeout)
++bool __mptcp_close(struct sock *sk, long timeout)
+ {
+ struct mptcp_subflow_context *subflow;
+ struct mptcp_sock *msk = mptcp_sk(sk);
+ bool do_cancel_work = false;
+
+- lock_sock(sk);
+ sk->sk_shutdown = SHUTDOWN_MASK;
+
+ if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) {
+@@ -2880,6 +2879,17 @@ cleanup:
+ } else {
+ mptcp_reset_timeout(msk, 0);
+ }
++
++ return do_cancel_work;
++}
++
++static void mptcp_close(struct sock *sk, long timeout)
++{
++ bool do_cancel_work;
++
++ lock_sock(sk);
++
++ do_cancel_work = __mptcp_close(sk, timeout);
+ release_sock(sk);
+ if (do_cancel_work)
+ mptcp_cancel_work(sk);
+diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
+index 092154d5bc752..d6bbc484420dc 100644
+--- a/net/mptcp/protocol.h
++++ b/net/mptcp/protocol.h
+@@ -613,6 +613,8 @@ void mptcp_subflow_reset(struct sock *ssk);
+ void mptcp_subflow_queue_clean(struct sock *ssk);
+ void mptcp_sock_graft(struct sock *sk, struct socket *parent);
+ struct socket *__mptcp_nmpc_socket(const struct mptcp_sock *msk);
++bool __mptcp_close(struct sock *sk, long timeout);
++void mptcp_cancel_work(struct sock *sk);
+
+ bool mptcp_addresses_equal(const struct mptcp_addr_info *a,
+ const struct mptcp_addr_info *b, bool use_port);
+diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
+index ac41b55b0a81a..6f603dbcf75c8 100644
+--- a/net/mptcp/subflow.c
++++ b/net/mptcp/subflow.c
+@@ -602,30 +602,6 @@ static bool subflow_hmac_valid(const struct request_sock *req,
+ return !crypto_memneq(hmac, mp_opt->hmac, MPTCPOPT_HMAC_LEN);
+ }
+
+-static void mptcp_sock_destruct(struct sock *sk)
+-{
+- /* if new mptcp socket isn't accepted, it is free'd
+- * from the tcp listener sockets request queue, linked
+- * from req->sk. The tcp socket is released.
+- * This calls the ULP release function which will
+- * also remove the mptcp socket, via
+- * sock_put(ctx->conn).
+- *
+- * Problem is that the mptcp socket will be in
+- * ESTABLISHED state and will not have the SOCK_DEAD flag.
+- * Both result in warnings from inet_sock_destruct.
+- */
+- if ((1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) {
+- sk->sk_state = TCP_CLOSE;
+- WARN_ON_ONCE(sk->sk_socket);
+- sock_orphan(sk);
+- }
+-
+- /* We don't need to clear msk->subflow, as it's still NULL at this point */
+- mptcp_destroy_common(mptcp_sk(sk), 0);
+- inet_sock_destruct(sk);
+-}
+-
+ static void mptcp_force_close(struct sock *sk)
+ {
+ /* the msk is not yet exposed to user-space */
+@@ -768,7 +744,6 @@ create_child:
+ /* new mpc subflow takes ownership of the newly
+ * created mptcp socket
+ */
+- new_msk->sk_destruct = mptcp_sock_destruct;
+ mptcp_sk(new_msk)->setsockopt_seq = ctx->setsockopt_seq;
+ mptcp_pm_new_connection(mptcp_sk(new_msk), child, 1);
+ mptcp_token_accept(subflow_req, mptcp_sk(new_msk));
+@@ -1763,13 +1738,19 @@ void mptcp_subflow_queue_clean(struct sock *listener_ssk)
+
+ for (msk = head; msk; msk = next) {
+ struct sock *sk = (struct sock *)msk;
+- bool slow;
++ bool slow, do_cancel_work;
+
++ sock_hold(sk);
+ slow = lock_sock_fast_nested(sk);
+ next = msk->dl_next;
+ msk->first = NULL;
+ msk->dl_next = NULL;
++
++ do_cancel_work = __mptcp_close(sk, 0);
+ unlock_sock_fast(sk, slow);
++ if (do_cancel_work)
++ mptcp_cancel_work(sk);
++ sock_put(sk);
+ }
+
+ /* we are still under the listener msk socket lock */
+diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c
+index e013253b10d18..4d44a1bf4a042 100644
+--- a/net/sched/act_ct.c
++++ b/net/sched/act_ct.c
+@@ -1393,7 +1393,7 @@ static int tcf_ct_init(struct net *net, struct nlattr *nla,
+
+ err = tcf_ct_flow_table_get(params);
+ if (err)
+- goto cleanup;
++ goto cleanup_params;
+
+ spin_lock_bh(&c->tcf_lock);
+ goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
+@@ -1408,6 +1408,9 @@ static int tcf_ct_init(struct net *net, struct nlattr *nla,
+
+ return res;
+
++cleanup_params:
++ if (params->tmpl)
++ nf_ct_put(params->tmpl);
+ cleanup:
+ if (goto_ch)
+ tcf_chain_put_by_act(goto_ch);
+diff --git a/net/wireless/util.c b/net/wireless/util.c
+index b7257862e0fe6..28b7f120501ae 100644
+--- a/net/wireless/util.c
++++ b/net/wireless/util.c
+@@ -1361,7 +1361,7 @@ static u32 cfg80211_calculate_bitrate_he(struct rate_info *rate)
+ 25599, /* 4.166666... */
+ 17067, /* 2.777777... */
+ 12801, /* 2.083333... */
+- 11769, /* 1.851851... */
++ 11377, /* 1.851725... */
+ 10239, /* 1.666666... */
+ 8532, /* 1.388888... */
+ 7680, /* 1.250000... */
+@@ -1444,7 +1444,7 @@ static u32 cfg80211_calculate_bitrate_eht(struct rate_info *rate)
+ 25599, /* 4.166666... */
+ 17067, /* 2.777777... */
+ 12801, /* 2.083333... */
+- 11769, /* 1.851851... */
++ 11377, /* 1.851725... */
+ 10239, /* 1.666666... */
+ 8532, /* 1.388888... */
+ 7680, /* 1.250000... */
+diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c
+index 9ea2aca65e899..e02ad765351b2 100644
+--- a/sound/soc/codecs/tas2770.c
++++ b/sound/soc/codecs/tas2770.c
+@@ -495,6 +495,8 @@ static struct snd_soc_dai_driver tas2770_dai_driver[] = {
+ },
+ };
+
++static const struct regmap_config tas2770_i2c_regmap;
++
+ static int tas2770_codec_probe(struct snd_soc_component *component)
+ {
+ struct tas2770_priv *tas2770 =
+@@ -508,6 +510,7 @@ static int tas2770_codec_probe(struct snd_soc_component *component)
+ }
+
+ tas2770_reset(tas2770);
++ regmap_reinit_cache(tas2770->regmap, &tas2770_i2c_regmap);
+
+ return 0;
+ }
+diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c
+index 4a8609b0d700d..5153af3281d23 100644
+--- a/sound/soc/fsl/imx-card.c
++++ b/sound/soc/fsl/imx-card.c
+@@ -698,6 +698,10 @@ static int imx_card_parse_of(struct imx_card_data *data)
+ of_node_put(cpu);
+ of_node_put(codec);
+ of_node_put(platform);
++
++ cpu = NULL;
++ codec = NULL;
++ platform = NULL;
+ }
+
+ return 0;
+diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
+index 468958154ed90..744dd35205847 100644
+--- a/tools/perf/builtin-list.c
++++ b/tools/perf/builtin-list.c
+@@ -10,7 +10,7 @@
+ */
+ #include "builtin.h"
+
+-#include "util/parse-events.h"
++#include "util/print-events.h"
+ #include "util/pmu.h"
+ #include "util/pmu-hybrid.h"
+ #include "util/debug.h"
+diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
+index 23a33ac15e685..dcc079a805851 100644
+--- a/tools/perf/builtin-lock.c
++++ b/tools/perf/builtin-lock.c
+@@ -13,6 +13,7 @@
+ #include <subcmd/pager.h>
+ #include <subcmd/parse-options.h>
+ #include "util/trace-event.h"
++#include "util/tracepoint.h"
+
+ #include "util/debug.h"
+ #include "util/session.h"
+diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
+index 68c878b4e5e4c..7fbc85c1da81e 100644
+--- a/tools/perf/builtin-record.c
++++ b/tools/perf/builtin-record.c
+@@ -3335,16 +3335,24 @@ static struct option __record_options[] = {
+
+ struct option *record_options = __record_options;
+
+-static void record__mmap_cpu_mask_init(struct mmap_cpu_mask *mask, struct perf_cpu_map *cpus)
++static int record__mmap_cpu_mask_init(struct mmap_cpu_mask *mask, struct perf_cpu_map *cpus)
+ {
+ struct perf_cpu cpu;
+ int idx;
+
+ if (cpu_map__is_dummy(cpus))
+- return;
++ return 0;
+
+- perf_cpu_map__for_each_cpu(cpu, idx, cpus)
++ perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
++ if (cpu.cpu == -1)
++ continue;
++ /* Return ENODEV is input cpu is greater than max cpu */
++ if ((unsigned long)cpu.cpu > mask->nbits)
++ return -ENODEV;
+ set_bit(cpu.cpu, mask->bits);
++ }
++
++ return 0;
+ }
+
+ static int record__mmap_cpu_mask_init_spec(struct mmap_cpu_mask *mask, const char *mask_spec)
+@@ -3356,7 +3364,9 @@ static int record__mmap_cpu_mask_init_spec(struct mmap_cpu_mask *mask, const cha
+ return -ENOMEM;
+
+ bitmap_zero(mask->bits, mask->nbits);
+- record__mmap_cpu_mask_init(mask, cpus);
++ if (record__mmap_cpu_mask_init(mask, cpus))
++ return -ENODEV;
++
+ perf_cpu_map__put(cpus);
+
+ return 0;
+@@ -3438,7 +3448,12 @@ static int record__init_thread_masks_spec(struct record *rec, struct perf_cpu_ma
+ pr_err("Failed to allocate CPUs mask\n");
+ return ret;
+ }
+- record__mmap_cpu_mask_init(&cpus_mask, cpus);
++
++ ret = record__mmap_cpu_mask_init(&cpus_mask, cpus);
++ if (ret) {
++ pr_err("Failed to init cpu mask\n");
++ goto out_free_cpu_mask;
++ }
+
+ ret = record__thread_mask_alloc(&full_mask, cpu__max_cpu().cpu);
+ if (ret) {
+@@ -3679,7 +3694,8 @@ static int record__init_thread_default_masks(struct record *rec, struct perf_cpu
+ if (ret)
+ return ret;
+
+- record__mmap_cpu_mask_init(&rec->thread_masks->maps, cpus);
++ if (record__mmap_cpu_mask_init(&rec->thread_masks->maps, cpus))
++ return -ENODEV;
+
+ rec->nr_threads = 1;
+
+diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
+index afce731cec16d..e2e9ad929bafa 100644
+--- a/tools/perf/builtin-timechart.c
++++ b/tools/perf/builtin-timechart.c
+@@ -36,6 +36,7 @@
+ #include "util/data.h"
+ #include "util/debug.h"
+ #include "util/string2.h"
++#include "util/tracepoint.h"
+ #include <linux/err.h>
+
+ #ifdef LACKS_OPEN_MEMSTREAM_PROTOTYPE
+diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
+index f075cf37a65ef..1e1f10a1971de 100644
+--- a/tools/perf/builtin-trace.c
++++ b/tools/perf/builtin-trace.c
+@@ -53,6 +53,7 @@
+ #include "trace-event.h"
+ #include "util/parse-events.h"
+ #include "util/bpf-loader.h"
++#include "util/tracepoint.h"
+ #include "callchain.h"
+ #include "print_binary.h"
+ #include "string2.h"
+diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
+index 6a001fcfed68e..4952abe716f31 100644
+--- a/tools/perf/tests/perf-record.c
++++ b/tools/perf/tests/perf-record.c
+@@ -332,7 +332,7 @@ out_delete_evlist:
+ out:
+ if (err == -EACCES)
+ return TEST_SKIP;
+- if (err < 0)
++ if (err < 0 || errs != 0)
+ return TEST_FAIL;
+ return TEST_OK;
+ }
+diff --git a/tools/perf/tests/shell/record.sh b/tools/perf/tests/shell/record.sh
+index 00c7285ce1ac6..301f95427159d 100755
+--- a/tools/perf/tests/shell/record.sh
++++ b/tools/perf/tests/shell/record.sh
+@@ -61,7 +61,7 @@ test_register_capture() {
+ echo "Register capture test [Skipped missing registers]"
+ return
+ fi
+- if ! perf record -o - --intr-regs=di,r8,dx,cx -e cpu/br_inst_retired.near_call/p \
++ if ! perf record -o - --intr-regs=di,r8,dx,cx -e br_inst_retired.near_call:p \
+ -c 1000 --per-thread true 2> /dev/null \
+ | perf script -F ip,sym,iregs -i - 2> /dev/null \
+ | egrep -q "DI:"
+diff --git a/tools/perf/util/Build b/tools/perf/util/Build
+index a51267d88ca90..038e4cf8f4885 100644
+--- a/tools/perf/util/Build
++++ b/tools/perf/util/Build
+@@ -26,6 +26,8 @@ perf-y += mmap.o
+ perf-y += memswap.o
+ perf-y += parse-events.o
+ perf-y += parse-events-hybrid.o
++perf-y += print-events.o
++perf-y += tracepoint.o
+ perf-y += perf_regs.o
+ perf-y += path.o
+ perf-y += print_binary.o
+diff --git a/tools/perf/util/parse-events-hybrid.c b/tools/perf/util/parse-events-hybrid.c
+index 284f8eabd3b9a..7c9f9150bad50 100644
+--- a/tools/perf/util/parse-events-hybrid.c
++++ b/tools/perf/util/parse-events-hybrid.c
+@@ -33,7 +33,8 @@ static void config_hybrid_attr(struct perf_event_attr *attr,
+ * If the PMU type ID is 0, the PERF_TYPE_RAW will be applied.
+ */
+ attr->type = type;
+- attr->config = attr->config | ((__u64)pmu_type << PERF_PMU_TYPE_SHIFT);
++ attr->config = (attr->config & PERF_HW_EVENT_MASK) |
++ ((__u64)pmu_type << PERF_PMU_TYPE_SHIFT);
+ }
+
+ static int create_event_hybrid(__u32 config_type, int *idx,
+@@ -48,13 +49,25 @@ static int create_event_hybrid(__u32 config_type, int *idx,
+ __u64 config = attr->config;
+
+ config_hybrid_attr(attr, config_type, pmu->type);
++
++ /*
++ * Some hybrid hardware cache events are only available on one CPU
++ * PMU. For example, the 'L1-dcache-load-misses' is only available
++ * on cpu_core, while the 'L1-icache-loads' is only available on
++ * cpu_atom. We need to remove "not supported" hybrid cache events.
++ */
++ if (attr->type == PERF_TYPE_HW_CACHE
++ && !is_event_supported(attr->type, attr->config))
++ return 0;
++
+ evsel = parse_events__add_event_hybrid(list, idx, attr, name, metric_id,
+ pmu, config_terms);
+- if (evsel)
++ if (evsel) {
+ evsel->pmu_name = strdup(pmu->name);
+- else
++ if (!evsel->pmu_name)
++ return -ENOMEM;
++ } else
+ return -ENOMEM;
+-
+ attr->type = type;
+ attr->config = config;
+ return 0;
+diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
+index 700c95eafd62a..b51c646c212e5 100644
+--- a/tools/perf/util/parse-events.c
++++ b/tools/perf/util/parse-events.c
+@@ -5,18 +5,12 @@
+ #include <dirent.h>
+ #include <errno.h>
+ #include <sys/ioctl.h>
+-#include <sys/types.h>
+-#include <sys/stat.h>
+-#include <fcntl.h>
+ #include <sys/param.h>
+ #include "term.h"
+-#include "build-id.h"
+ #include "evlist.h"
+ #include "evsel.h"
+-#include <subcmd/pager.h>
+ #include <subcmd/parse-options.h>
+ #include "parse-events.h"
+-#include <subcmd/exec-cmd.h>
+ #include "string2.h"
+ #include "strlist.h"
+ #include "bpf-loader.h"
+@@ -27,20 +21,23 @@
+ #define YY_EXTRA_TYPE void*
+ #include "parse-events-flex.h"
+ #include "pmu.h"
+-#include "thread_map.h"
+-#include "probe-file.h"
+ #include "asm/bug.h"
+ #include "util/parse-branch-options.h"
+-#include "metricgroup.h"
+ #include "util/evsel_config.h"
+ #include "util/event.h"
+-#include "util/pfm.h"
++#include "perf.h"
+ #include "util/parse-events-hybrid.h"
+ #include "util/pmu-hybrid.h"
+-#include "perf.h"
++#include "tracepoint.h"
++#include "thread_map.h"
+
+ #define MAX_NAME_LEN 100
+
++struct perf_pmu_event_symbol {
++ char *symbol;
++ enum perf_pmu_event_symbol_type type;
++};
++
+ #ifdef PARSER_DEBUG
+ extern int parse_events_debug;
+ #endif
+@@ -154,21 +151,6 @@ struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = {
+ },
+ };
+
+-struct event_symbol event_symbols_tool[PERF_TOOL_MAX] = {
+- [PERF_TOOL_DURATION_TIME] = {
+- .symbol = "duration_time",
+- .alias = "",
+- },
+- [PERF_TOOL_USER_TIME] = {
+- .symbol = "user_time",
+- .alias = "",
+- },
+- [PERF_TOOL_SYSTEM_TIME] = {
+- .symbol = "system_time",
+- .alias = "",
+- },
+-};
+-
+ #define __PERF_EVENT_FIELD(config, name) \
+ ((config & PERF_EVENT_##name##_MASK) >> PERF_EVENT_##name##_SHIFT)
+
+@@ -177,119 +159,42 @@ struct event_symbol event_symbols_tool[PERF_TOOL_MAX] = {
+ #define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE)
+ #define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT)
+
+-#define for_each_subsystem(sys_dir, sys_dirent) \
+- while ((sys_dirent = readdir(sys_dir)) != NULL) \
+- if (sys_dirent->d_type == DT_DIR && \
+- (strcmp(sys_dirent->d_name, ".")) && \
+- (strcmp(sys_dirent->d_name, "..")))
+-
+-static int tp_event_has_id(const char *dir_path, struct dirent *evt_dir)
+-{
+- char evt_path[MAXPATHLEN];
+- int fd;
+-
+- snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, evt_dir->d_name);
+- fd = open(evt_path, O_RDONLY);
+- if (fd < 0)
+- return -EINVAL;
+- close(fd);
+-
+- return 0;
+-}
+-
+-#define for_each_event(dir_path, evt_dir, evt_dirent) \
+- while ((evt_dirent = readdir(evt_dir)) != NULL) \
+- if (evt_dirent->d_type == DT_DIR && \
+- (strcmp(evt_dirent->d_name, ".")) && \
+- (strcmp(evt_dirent->d_name, "..")) && \
+- (!tp_event_has_id(dir_path, evt_dirent)))
+-
+-#define MAX_EVENT_LENGTH 512
+-
+-struct tracepoint_path *tracepoint_id_to_path(u64 config)
++bool is_event_supported(u8 type, u64 config)
+ {
+- struct tracepoint_path *path = NULL;
+- DIR *sys_dir, *evt_dir;
+- struct dirent *sys_dirent, *evt_dirent;
+- char id_buf[24];
+- int fd;
+- u64 id;
+- char evt_path[MAXPATHLEN];
+- char *dir_path;
+-
+- sys_dir = tracing_events__opendir();
+- if (!sys_dir)
+- return NULL;
++ bool ret = true;
++ int open_return;
++ struct evsel *evsel;
++ struct perf_event_attr attr = {
++ .type = type,
++ .config = config,
++ .disabled = 1,
++ };
++ struct perf_thread_map *tmap = thread_map__new_by_tid(0);
+
+- for_each_subsystem(sys_dir, sys_dirent) {
+- dir_path = get_events_file(sys_dirent->d_name);
+- if (!dir_path)
+- continue;
+- evt_dir = opendir(dir_path);
+- if (!evt_dir)
+- goto next;
++ if (tmap == NULL)
++ return false;
+
+- for_each_event(dir_path, evt_dir, evt_dirent) {
++ evsel = evsel__new(&attr);
++ if (evsel) {
++ open_return = evsel__open(evsel, NULL, tmap);
++ ret = open_return >= 0;
+
+- scnprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path,
+- evt_dirent->d_name);
+- fd = open(evt_path, O_RDONLY);
+- if (fd < 0)
+- continue;
+- if (read(fd, id_buf, sizeof(id_buf)) < 0) {
+- close(fd);
+- continue;
+- }
+- close(fd);
+- id = atoll(id_buf);
+- if (id == config) {
+- put_events_file(dir_path);
+- closedir(evt_dir);
+- closedir(sys_dir);
+- path = zalloc(sizeof(*path));
+- if (!path)
+- return NULL;
+- if (asprintf(&path->system, "%.*s", MAX_EVENT_LENGTH, sys_dirent->d_name) < 0) {
+- free(path);
+- return NULL;
+- }
+- if (asprintf(&path->name, "%.*s", MAX_EVENT_LENGTH, evt_dirent->d_name) < 0) {
+- zfree(&path->system);
+- free(path);
+- return NULL;
+- }
+- return path;
+- }
++ if (open_return == -EACCES) {
++ /*
++ * This happens if the paranoid value
++ * /proc/sys/kernel/perf_event_paranoid is set to 2
++ * Re-run with exclude_kernel set; we don't do that
++ * by default as some ARM machines do not support it.
++ *
++ */
++ evsel->core.attr.exclude_kernel = 1;
++ ret = evsel__open(evsel, NULL, tmap) >= 0;
+ }
+- closedir(evt_dir);
+-next:
+- put_events_file(dir_path);
+- }
+-
+- closedir(sys_dir);
+- return NULL;
+-}
+-
+-struct tracepoint_path *tracepoint_name_to_path(const char *name)
+-{
+- struct tracepoint_path *path = zalloc(sizeof(*path));
+- char *str = strchr(name, ':');
+-
+- if (path == NULL || str == NULL) {
+- free(path);
+- return NULL;
+- }
+-
+- path->system = strndup(name, str - name);
+- path->name = strdup(str+1);
+-
+- if (path->system == NULL || path->name == NULL) {
+- zfree(&path->system);
+- zfree(&path->name);
+- zfree(&path);
++ evsel__delete(evsel);
+ }
+
+- return path;
++ perf_thread_map__put(tmap);
++ return ret;
+ }
+
+ const char *event_type(int type)
+@@ -2674,571 +2579,6 @@ int exclude_perf(const struct option *opt,
+ NULL);
+ }
+
+-static const char * const event_type_descriptors[] = {
+- "Hardware event",
+- "Software event",
+- "Tracepoint event",
+- "Hardware cache event",
+- "Raw hardware event descriptor",
+- "Hardware breakpoint",
+-};
+-
+-static int cmp_string(const void *a, const void *b)
+-{
+- const char * const *as = a;
+- const char * const *bs = b;
+-
+- return strcmp(*as, *bs);
+-}
+-
+-/*
+- * Print the events from <debugfs_mount_point>/tracing/events
+- */
+-
+-void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
+- bool name_only)
+-{
+- DIR *sys_dir, *evt_dir;
+- struct dirent *sys_dirent, *evt_dirent;
+- char evt_path[MAXPATHLEN];
+- char *dir_path;
+- char **evt_list = NULL;
+- unsigned int evt_i = 0, evt_num = 0;
+- bool evt_num_known = false;
+-
+-restart:
+- sys_dir = tracing_events__opendir();
+- if (!sys_dir)
+- return;
+-
+- if (evt_num_known) {
+- evt_list = zalloc(sizeof(char *) * evt_num);
+- if (!evt_list)
+- goto out_close_sys_dir;
+- }
+-
+- for_each_subsystem(sys_dir, sys_dirent) {
+- if (subsys_glob != NULL &&
+- !strglobmatch(sys_dirent->d_name, subsys_glob))
+- continue;
+-
+- dir_path = get_events_file(sys_dirent->d_name);
+- if (!dir_path)
+- continue;
+- evt_dir = opendir(dir_path);
+- if (!evt_dir)
+- goto next;
+-
+- for_each_event(dir_path, evt_dir, evt_dirent) {
+- if (event_glob != NULL &&
+- !strglobmatch(evt_dirent->d_name, event_glob))
+- continue;
+-
+- if (!evt_num_known) {
+- evt_num++;
+- continue;
+- }
+-
+- snprintf(evt_path, MAXPATHLEN, "%s:%s",
+- sys_dirent->d_name, evt_dirent->d_name);
+-
+- evt_list[evt_i] = strdup(evt_path);
+- if (evt_list[evt_i] == NULL) {
+- put_events_file(dir_path);
+- goto out_close_evt_dir;
+- }
+- evt_i++;
+- }
+- closedir(evt_dir);
+-next:
+- put_events_file(dir_path);
+- }
+- closedir(sys_dir);
+-
+- if (!evt_num_known) {
+- evt_num_known = true;
+- goto restart;
+- }
+- qsort(evt_list, evt_num, sizeof(char *), cmp_string);
+- evt_i = 0;
+- while (evt_i < evt_num) {
+- if (name_only) {
+- printf("%s ", evt_list[evt_i++]);
+- continue;
+- }
+- printf(" %-50s [%s]\n", evt_list[evt_i++],
+- event_type_descriptors[PERF_TYPE_TRACEPOINT]);
+- }
+- if (evt_num && pager_in_use())
+- printf("\n");
+-
+-out_free:
+- evt_num = evt_i;
+- for (evt_i = 0; evt_i < evt_num; evt_i++)
+- zfree(&evt_list[evt_i]);
+- zfree(&evt_list);
+- return;
+-
+-out_close_evt_dir:
+- closedir(evt_dir);
+-out_close_sys_dir:
+- closedir(sys_dir);
+-
+- printf("FATAL: not enough memory to print %s\n",
+- event_type_descriptors[PERF_TYPE_TRACEPOINT]);
+- if (evt_list)
+- goto out_free;
+-}
+-
+-/*
+- * Check whether event is in <debugfs_mount_point>/tracing/events
+- */
+-
+-int is_valid_tracepoint(const char *event_string)
+-{
+- DIR *sys_dir, *evt_dir;
+- struct dirent *sys_dirent, *evt_dirent;
+- char evt_path[MAXPATHLEN];
+- char *dir_path;
+-
+- sys_dir = tracing_events__opendir();
+- if (!sys_dir)
+- return 0;
+-
+- for_each_subsystem(sys_dir, sys_dirent) {
+- dir_path = get_events_file(sys_dirent->d_name);
+- if (!dir_path)
+- continue;
+- evt_dir = opendir(dir_path);
+- if (!evt_dir)
+- goto next;
+-
+- for_each_event(dir_path, evt_dir, evt_dirent) {
+- snprintf(evt_path, MAXPATHLEN, "%s:%s",
+- sys_dirent->d_name, evt_dirent->d_name);
+- if (!strcmp(evt_path, event_string)) {
+- closedir(evt_dir);
+- closedir(sys_dir);
+- return 1;
+- }
+- }
+- closedir(evt_dir);
+-next:
+- put_events_file(dir_path);
+- }
+- closedir(sys_dir);
+- return 0;
+-}
+-
+-static bool is_event_supported(u8 type, u64 config)
+-{
+- bool ret = true;
+- int open_return;
+- struct evsel *evsel;
+- struct perf_event_attr attr = {
+- .type = type,
+- .config = config,
+- .disabled = 1,
+- };
+- struct perf_thread_map *tmap = thread_map__new_by_tid(0);
+-
+- if (tmap == NULL)
+- return false;
+-
+- evsel = evsel__new(&attr);
+- if (evsel) {
+- open_return = evsel__open(evsel, NULL, tmap);
+- ret = open_return >= 0;
+-
+- if (open_return == -EACCES) {
+- /*
+- * This happens if the paranoid value
+- * /proc/sys/kernel/perf_event_paranoid is set to 2
+- * Re-run with exclude_kernel set; we don't do that
+- * by default as some ARM machines do not support it.
+- *
+- */
+- evsel->core.attr.exclude_kernel = 1;
+- ret = evsel__open(evsel, NULL, tmap) >= 0;
+- }
+- evsel__delete(evsel);
+- }
+-
+- perf_thread_map__put(tmap);
+- return ret;
+-}
+-
+-void print_sdt_events(const char *subsys_glob, const char *event_glob,
+- bool name_only)
+-{
+- struct probe_cache *pcache;
+- struct probe_cache_entry *ent;
+- struct strlist *bidlist, *sdtlist;
+- struct strlist_config cfg = {.dont_dupstr = true};
+- struct str_node *nd, *nd2;
+- char *buf, *path, *ptr = NULL;
+- bool show_detail = false;
+- int ret;
+-
+- sdtlist = strlist__new(NULL, &cfg);
+- if (!sdtlist) {
+- pr_debug("Failed to allocate new strlist for SDT\n");
+- return;
+- }
+- bidlist = build_id_cache__list_all(true);
+- if (!bidlist) {
+- pr_debug("Failed to get buildids: %d\n", errno);
+- return;
+- }
+- strlist__for_each_entry(nd, bidlist) {
+- pcache = probe_cache__new(nd->s, NULL);
+- if (!pcache)
+- continue;
+- list_for_each_entry(ent, &pcache->entries, node) {
+- if (!ent->sdt)
+- continue;
+- if (subsys_glob &&
+- !strglobmatch(ent->pev.group, subsys_glob))
+- continue;
+- if (event_glob &&
+- !strglobmatch(ent->pev.event, event_glob))
+- continue;
+- ret = asprintf(&buf, "%s:%s@%s", ent->pev.group,
+- ent->pev.event, nd->s);
+- if (ret > 0)
+- strlist__add(sdtlist, buf);
+- }
+- probe_cache__delete(pcache);
+- }
+- strlist__delete(bidlist);
+-
+- strlist__for_each_entry(nd, sdtlist) {
+- buf = strchr(nd->s, '@');
+- if (buf)
+- *(buf++) = '\0';
+- if (name_only) {
+- printf("%s ", nd->s);
+- continue;
+- }
+- nd2 = strlist__next(nd);
+- if (nd2) {
+- ptr = strchr(nd2->s, '@');
+- if (ptr)
+- *ptr = '\0';
+- if (strcmp(nd->s, nd2->s) == 0)
+- show_detail = true;
+- }
+- if (show_detail) {
+- path = build_id_cache__origname(buf);
+- ret = asprintf(&buf, "%s@%s(%.12s)", nd->s, path, buf);
+- if (ret > 0) {
+- printf(" %-50s [%s]\n", buf, "SDT event");
+- free(buf);
+- }
+- free(path);
+- } else
+- printf(" %-50s [%s]\n", nd->s, "SDT event");
+- if (nd2) {
+- if (strcmp(nd->s, nd2->s) != 0)
+- show_detail = false;
+- if (ptr)
+- *ptr = '@';
+- }
+- }
+- strlist__delete(sdtlist);
+-}
+-
+-int print_hwcache_events(const char *event_glob, bool name_only)
+-{
+- unsigned int type, op, i, evt_i = 0, evt_num = 0, npmus = 0;
+- char name[64], new_name[128];
+- char **evt_list = NULL, **evt_pmus = NULL;
+- bool evt_num_known = false;
+- struct perf_pmu *pmu = NULL;
+-
+- if (perf_pmu__has_hybrid()) {
+- npmus = perf_pmu__hybrid_pmu_num();
+- evt_pmus = zalloc(sizeof(char *) * npmus);
+- if (!evt_pmus)
+- goto out_enomem;
+- }
+-
+-restart:
+- if (evt_num_known) {
+- evt_list = zalloc(sizeof(char *) * evt_num);
+- if (!evt_list)
+- goto out_enomem;
+- }
+-
+- for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
+- for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
+- /* skip invalid cache type */
+- if (!evsel__is_cache_op_valid(type, op))
+- continue;
+-
+- for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
+- unsigned int hybrid_supported = 0, j;
+- bool supported;
+-
+- __evsel__hw_cache_type_op_res_name(type, op, i, name, sizeof(name));
+- if (event_glob != NULL && !strglobmatch(name, event_glob))
+- continue;
+-
+- if (!perf_pmu__has_hybrid()) {
+- if (!is_event_supported(PERF_TYPE_HW_CACHE,
+- type | (op << 8) | (i << 16))) {
+- continue;
+- }
+- } else {
+- perf_pmu__for_each_hybrid_pmu(pmu) {
+- if (!evt_num_known) {
+- evt_num++;
+- continue;
+- }
+-
+- supported = is_event_supported(
+- PERF_TYPE_HW_CACHE,
+- type | (op << 8) | (i << 16) |
+- ((__u64)pmu->type << PERF_PMU_TYPE_SHIFT));
+- if (supported) {
+- snprintf(new_name, sizeof(new_name), "%s/%s/",
+- pmu->name, name);
+- evt_pmus[hybrid_supported] = strdup(new_name);
+- hybrid_supported++;
+- }
+- }
+-
+- if (hybrid_supported == 0)
+- continue;
+- }
+-
+- if (!evt_num_known) {
+- evt_num++;
+- continue;
+- }
+-
+- if ((hybrid_supported == 0) ||
+- (hybrid_supported == npmus)) {
+- evt_list[evt_i] = strdup(name);
+- if (npmus > 0) {
+- for (j = 0; j < npmus; j++)
+- zfree(&evt_pmus[j]);
+- }
+- } else {
+- for (j = 0; j < hybrid_supported; j++) {
+- evt_list[evt_i++] = evt_pmus[j];
+- evt_pmus[j] = NULL;
+- }
+- continue;
+- }
+-
+- if (evt_list[evt_i] == NULL)
+- goto out_enomem;
+- evt_i++;
+- }
+- }
+- }
+-
+- if (!evt_num_known) {
+- evt_num_known = true;
+- goto restart;
+- }
+-
+- for (evt_i = 0; evt_i < evt_num; evt_i++) {
+- if (!evt_list[evt_i])
+- break;
+- }
+-
+- evt_num = evt_i;
+- qsort(evt_list, evt_num, sizeof(char *), cmp_string);
+- evt_i = 0;
+- while (evt_i < evt_num) {
+- if (name_only) {
+- printf("%s ", evt_list[evt_i++]);
+- continue;
+- }
+- printf(" %-50s [%s]\n", evt_list[evt_i++],
+- event_type_descriptors[PERF_TYPE_HW_CACHE]);
+- }
+- if (evt_num && pager_in_use())
+- printf("\n");
+-
+-out_free:
+- evt_num = evt_i;
+- for (evt_i = 0; evt_i < evt_num; evt_i++)
+- zfree(&evt_list[evt_i]);
+- zfree(&evt_list);
+-
+- for (evt_i = 0; evt_i < npmus; evt_i++)
+- zfree(&evt_pmus[evt_i]);
+- zfree(&evt_pmus);
+- return evt_num;
+-
+-out_enomem:
+- printf("FATAL: not enough memory to print %s\n", event_type_descriptors[PERF_TYPE_HW_CACHE]);
+- if (evt_list)
+- goto out_free;
+- return evt_num;
+-}
+-
+-static void print_tool_event(const struct event_symbol *syms, const char *event_glob,
+- bool name_only)
+-{
+- if (syms->symbol == NULL)
+- return;
+-
+- if (event_glob && !(strglobmatch(syms->symbol, event_glob) ||
+- (syms->alias && strglobmatch(syms->alias, event_glob))))
+- return;
+-
+- if (name_only)
+- printf("%s ", syms->symbol);
+- else {
+- char name[MAX_NAME_LEN];
+- if (syms->alias && strlen(syms->alias))
+- snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias);
+- else
+- strlcpy(name, syms->symbol, MAX_NAME_LEN);
+- printf(" %-50s [%s]\n", name, "Tool event");
+- }
+-}
+-
+-void print_tool_events(const char *event_glob, bool name_only)
+-{
+- // Start at 1 because the first enum entry symbols no tool event
+- for (int i = 1; i < PERF_TOOL_MAX; ++i) {
+- print_tool_event(event_symbols_tool + i, event_glob, name_only);
+- }
+- if (pager_in_use())
+- printf("\n");
+-}
+-
+-void print_symbol_events(const char *event_glob, unsigned type,
+- struct event_symbol *syms, unsigned max,
+- bool name_only)
+-{
+- unsigned int i, evt_i = 0, evt_num = 0;
+- char name[MAX_NAME_LEN];
+- char **evt_list = NULL;
+- bool evt_num_known = false;
+-
+-restart:
+- if (evt_num_known) {
+- evt_list = zalloc(sizeof(char *) * evt_num);
+- if (!evt_list)
+- goto out_enomem;
+- syms -= max;
+- }
+-
+- for (i = 0; i < max; i++, syms++) {
+- /*
+- * New attr.config still not supported here, the latest
+- * example was PERF_COUNT_SW_CGROUP_SWITCHES
+- */
+- if (syms->symbol == NULL)
+- continue;
+-
+- if (event_glob != NULL && !(strglobmatch(syms->symbol, event_glob) ||
+- (syms->alias && strglobmatch(syms->alias, event_glob))))
+- continue;
+-
+- if (!is_event_supported(type, i))
+- continue;
+-
+- if (!evt_num_known) {
+- evt_num++;
+- continue;
+- }
+-
+- if (!name_only && strlen(syms->alias))
+- snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias);
+- else
+- strlcpy(name, syms->symbol, MAX_NAME_LEN);
+-
+- evt_list[evt_i] = strdup(name);
+- if (evt_list[evt_i] == NULL)
+- goto out_enomem;
+- evt_i++;
+- }
+-
+- if (!evt_num_known) {
+- evt_num_known = true;
+- goto restart;
+- }
+- qsort(evt_list, evt_num, sizeof(char *), cmp_string);
+- evt_i = 0;
+- while (evt_i < evt_num) {
+- if (name_only) {
+- printf("%s ", evt_list[evt_i++]);
+- continue;
+- }
+- printf(" %-50s [%s]\n", evt_list[evt_i++], event_type_descriptors[type]);
+- }
+- if (evt_num && pager_in_use())
+- printf("\n");
+-
+-out_free:
+- evt_num = evt_i;
+- for (evt_i = 0; evt_i < evt_num; evt_i++)
+- zfree(&evt_list[evt_i]);
+- zfree(&evt_list);
+- return;
+-
+-out_enomem:
+- printf("FATAL: not enough memory to print %s\n", event_type_descriptors[type]);
+- if (evt_list)
+- goto out_free;
+-}
+-
+-/*
+- * Print the help text for the event symbols:
+- */
+-void print_events(const char *event_glob, bool name_only, bool quiet_flag,
+- bool long_desc, bool details_flag, bool deprecated,
+- const char *pmu_name)
+-{
+- print_symbol_events(event_glob, PERF_TYPE_HARDWARE,
+- event_symbols_hw, PERF_COUNT_HW_MAX, name_only);
+-
+- print_symbol_events(event_glob, PERF_TYPE_SOFTWARE,
+- event_symbols_sw, PERF_COUNT_SW_MAX, name_only);
+- print_tool_events(event_glob, name_only);
+-
+- print_hwcache_events(event_glob, name_only);
+-
+- print_pmu_events(event_glob, name_only, quiet_flag, long_desc,
+- details_flag, deprecated, pmu_name);
+-
+- if (event_glob != NULL)
+- return;
+-
+- if (!name_only) {
+- printf(" %-50s [%s]\n",
+- "rNNN",
+- event_type_descriptors[PERF_TYPE_RAW]);
+- printf(" %-50s [%s]\n",
+- "cpu/t1=v1[,t2=v2,t3 ...]/modifier",
+- event_type_descriptors[PERF_TYPE_RAW]);
+- if (pager_in_use())
+- printf(" (see 'man perf-list' on how to encode it)\n\n");
+-
+- printf(" %-50s [%s]\n",
+- "mem:<addr>[/len][:access]",
+- event_type_descriptors[PERF_TYPE_BREAKPOINT]);
+- if (pager_in_use())
+- printf("\n");
+- }
+-
+- print_tracepoint_events(NULL, NULL, name_only);
+-
+- print_sdt_events(NULL, NULL, name_only);
+-
+- metricgroup__print(true, true, NULL, name_only, details_flag,
+- pmu_name);
+-
+- print_libpfm_events(name_only, long_desc);
+-}
+-
+ int parse_events__is_hardcoded_term(struct parse_events_term *term)
+ {
+ return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
+diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
+index a38b8b160e80b..fd97bb74559e6 100644
+--- a/tools/perf/util/parse-events.h
++++ b/tools/perf/util/parse-events.h
+@@ -11,7 +11,6 @@
+ #include <linux/perf_event.h>
+ #include <string.h>
+
+-struct list_head;
+ struct evsel;
+ struct evlist;
+ struct parse_events_error;
+@@ -19,15 +18,8 @@ struct parse_events_error;
+ struct option;
+ struct perf_pmu;
+
+-struct tracepoint_path {
+- char *system;
+- char *name;
+- struct tracepoint_path *next;
+-};
+-
+-struct tracepoint_path *tracepoint_id_to_path(u64 config);
+-struct tracepoint_path *tracepoint_name_to_path(const char *name);
+ bool have_tracepoints(struct list_head *evlist);
++bool is_event_supported(u8 type, u64 config);
+
+ const char *event_type(int type);
+
+@@ -46,8 +38,6 @@ int parse_events_terms(struct list_head *terms, const char *str);
+ int parse_filter(const struct option *opt, const char *str, int unset);
+ int exclude_perf(const struct option *opt, const char *arg, int unset);
+
+-#define EVENTS_HELP_MAX (128*1024)
+-
+ enum perf_pmu_event_symbol_type {
+ PMU_EVENT_SYMBOL_ERR, /* not a PMU EVENT */
+ PMU_EVENT_SYMBOL, /* normal style PMU event */
+@@ -56,11 +46,6 @@ enum perf_pmu_event_symbol_type {
+ PMU_EVENT_SYMBOL_SUFFIX2, /* suffix of pre-suf2 style event */
+ };
+
+-struct perf_pmu_event_symbol {
+- char *symbol;
+- enum perf_pmu_event_symbol_type type;
+-};
+-
+ enum {
+ PARSE_EVENTS__TERM_TYPE_NUM,
+ PARSE_EVENTS__TERM_TYPE_STR,
+@@ -219,28 +204,13 @@ void parse_events_update_lists(struct list_head *list_event,
+ void parse_events_evlist_error(struct parse_events_state *parse_state,
+ int idx, const char *str);
+
+-void print_events(const char *event_glob, bool name_only, bool quiet,
+- bool long_desc, bool details_flag, bool deprecated,
+- const char *pmu_name);
+-
+ struct event_symbol {
+ const char *symbol;
+ const char *alias;
+ };
+ extern struct event_symbol event_symbols_hw[];
+ extern struct event_symbol event_symbols_sw[];
+-void print_symbol_events(const char *event_glob, unsigned type,
+- struct event_symbol *syms, unsigned max,
+- bool name_only);
+-void print_tool_events(const char *event_glob, bool name_only);
+-void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
+- bool name_only);
+-int print_hwcache_events(const char *event_glob, bool name_only);
+-void print_sdt_events(const char *subsys_glob, const char *event_glob,
+- bool name_only);
+-int is_valid_tracepoint(const char *event_string);
+
+-int valid_event_mount(const char *eventfs);
+ char *parse_events_formats_error_string(char *additional_terms);
+
+ void parse_events_error__init(struct parse_events_error *err);
+diff --git a/tools/perf/util/print-events.c b/tools/perf/util/print-events.c
+new file mode 100644
+index 0000000000000..c4d5d87fae2f6
+--- /dev/null
++++ b/tools/perf/util/print-events.c
+@@ -0,0 +1,533 @@
++// SPDX-License-Identifier: GPL-2.0
++#include <dirent.h>
++#include <errno.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/param.h>
++
++#include <api/fs/tracing_path.h>
++#include <linux/stddef.h>
++#include <linux/perf_event.h>
++#include <linux/zalloc.h>
++#include <subcmd/pager.h>
++
++#include "build-id.h"
++#include "debug.h"
++#include "evsel.h"
++#include "metricgroup.h"
++#include "parse-events.h"
++#include "pmu.h"
++#include "print-events.h"
++#include "probe-file.h"
++#include "string2.h"
++#include "strlist.h"
++#include "tracepoint.h"
++#include "pfm.h"
++#include "pmu-hybrid.h"
++
++#define MAX_NAME_LEN 100
++
++static const char * const event_type_descriptors[] = {
++ "Hardware event",
++ "Software event",
++ "Tracepoint event",
++ "Hardware cache event",
++ "Raw hardware event descriptor",
++ "Hardware breakpoint",
++};
++
++static const struct event_symbol event_symbols_tool[PERF_TOOL_MAX] = {
++ [PERF_TOOL_DURATION_TIME] = {
++ .symbol = "duration_time",
++ .alias = "",
++ },
++ [PERF_TOOL_USER_TIME] = {
++ .symbol = "user_time",
++ .alias = "",
++ },
++ [PERF_TOOL_SYSTEM_TIME] = {
++ .symbol = "system_time",
++ .alias = "",
++ },
++};
++
++static int cmp_string(const void *a, const void *b)
++{
++ const char * const *as = a;
++ const char * const *bs = b;
++
++ return strcmp(*as, *bs);
++}
++
++/*
++ * Print the events from <debugfs_mount_point>/tracing/events
++ */
++void print_tracepoint_events(const char *subsys_glob,
++ const char *event_glob, bool name_only)
++{
++ DIR *sys_dir, *evt_dir;
++ struct dirent *sys_dirent, *evt_dirent;
++ char evt_path[MAXPATHLEN];
++ char *dir_path;
++ char **evt_list = NULL;
++ unsigned int evt_i = 0, evt_num = 0;
++ bool evt_num_known = false;
++
++restart:
++ sys_dir = tracing_events__opendir();
++ if (!sys_dir)
++ return;
++
++ if (evt_num_known) {
++ evt_list = zalloc(sizeof(char *) * evt_num);
++ if (!evt_list)
++ goto out_close_sys_dir;
++ }
++
++ for_each_subsystem(sys_dir, sys_dirent) {
++ if (subsys_glob != NULL &&
++ !strglobmatch(sys_dirent->d_name, subsys_glob))
++ continue;
++
++ dir_path = get_events_file(sys_dirent->d_name);
++ if (!dir_path)
++ continue;
++ evt_dir = opendir(dir_path);
++ if (!evt_dir)
++ goto next;
++
++ for_each_event(dir_path, evt_dir, evt_dirent) {
++ if (event_glob != NULL &&
++ !strglobmatch(evt_dirent->d_name, event_glob))
++ continue;
++
++ if (!evt_num_known) {
++ evt_num++;
++ continue;
++ }
++
++ snprintf(evt_path, MAXPATHLEN, "%s:%s",
++ sys_dirent->d_name, evt_dirent->d_name);
++
++ evt_list[evt_i] = strdup(evt_path);
++ if (evt_list[evt_i] == NULL) {
++ put_events_file(dir_path);
++ goto out_close_evt_dir;
++ }
++ evt_i++;
++ }
++ closedir(evt_dir);
++next:
++ put_events_file(dir_path);
++ }
++ closedir(sys_dir);
++
++ if (!evt_num_known) {
++ evt_num_known = true;
++ goto restart;
++ }
++ qsort(evt_list, evt_num, sizeof(char *), cmp_string);
++ evt_i = 0;
++ while (evt_i < evt_num) {
++ if (name_only) {
++ printf("%s ", evt_list[evt_i++]);
++ continue;
++ }
++ printf(" %-50s [%s]\n", evt_list[evt_i++],
++ event_type_descriptors[PERF_TYPE_TRACEPOINT]);
++ }
++ if (evt_num && pager_in_use())
++ printf("\n");
++
++out_free:
++ evt_num = evt_i;
++ for (evt_i = 0; evt_i < evt_num; evt_i++)
++ zfree(&evt_list[evt_i]);
++ zfree(&evt_list);
++ return;
++
++out_close_evt_dir:
++ closedir(evt_dir);
++out_close_sys_dir:
++ closedir(sys_dir);
++
++ printf("FATAL: not enough memory to print %s\n",
++ event_type_descriptors[PERF_TYPE_TRACEPOINT]);
++ if (evt_list)
++ goto out_free;
++}
++
++void print_sdt_events(const char *subsys_glob, const char *event_glob,
++ bool name_only)
++{
++ struct probe_cache *pcache;
++ struct probe_cache_entry *ent;
++ struct strlist *bidlist, *sdtlist;
++ struct strlist_config cfg = {.dont_dupstr = true};
++ struct str_node *nd, *nd2;
++ char *buf, *path, *ptr = NULL;
++ bool show_detail = false;
++ int ret;
++
++ sdtlist = strlist__new(NULL, &cfg);
++ if (!sdtlist) {
++ pr_debug("Failed to allocate new strlist for SDT\n");
++ return;
++ }
++ bidlist = build_id_cache__list_all(true);
++ if (!bidlist) {
++ pr_debug("Failed to get buildids: %d\n", errno);
++ return;
++ }
++ strlist__for_each_entry(nd, bidlist) {
++ pcache = probe_cache__new(nd->s, NULL);
++ if (!pcache)
++ continue;
++ list_for_each_entry(ent, &pcache->entries, node) {
++ if (!ent->sdt)
++ continue;
++ if (subsys_glob &&
++ !strglobmatch(ent->pev.group, subsys_glob))
++ continue;
++ if (event_glob &&
++ !strglobmatch(ent->pev.event, event_glob))
++ continue;
++ ret = asprintf(&buf, "%s:%s@%s", ent->pev.group,
++ ent->pev.event, nd->s);
++ if (ret > 0)
++ strlist__add(sdtlist, buf);
++ }
++ probe_cache__delete(pcache);
++ }
++ strlist__delete(bidlist);
++
++ strlist__for_each_entry(nd, sdtlist) {
++ buf = strchr(nd->s, '@');
++ if (buf)
++ *(buf++) = '\0';
++ if (name_only) {
++ printf("%s ", nd->s);
++ continue;
++ }
++ nd2 = strlist__next(nd);
++ if (nd2) {
++ ptr = strchr(nd2->s, '@');
++ if (ptr)
++ *ptr = '\0';
++ if (strcmp(nd->s, nd2->s) == 0)
++ show_detail = true;
++ }
++ if (show_detail) {
++ path = build_id_cache__origname(buf);
++ ret = asprintf(&buf, "%s@%s(%.12s)", nd->s, path, buf);
++ if (ret > 0) {
++ printf(" %-50s [%s]\n", buf, "SDT event");
++ free(buf);
++ }
++ free(path);
++ } else
++ printf(" %-50s [%s]\n", nd->s, "SDT event");
++ if (nd2) {
++ if (strcmp(nd->s, nd2->s) != 0)
++ show_detail = false;
++ if (ptr)
++ *ptr = '@';
++ }
++ }
++ strlist__delete(sdtlist);
++}
++
++int print_hwcache_events(const char *event_glob, bool name_only)
++{
++ unsigned int type, op, i, evt_i = 0, evt_num = 0, npmus = 0;
++ char name[64], new_name[128];
++ char **evt_list = NULL, **evt_pmus = NULL;
++ bool evt_num_known = false;
++ struct perf_pmu *pmu = NULL;
++
++ if (perf_pmu__has_hybrid()) {
++ npmus = perf_pmu__hybrid_pmu_num();
++ evt_pmus = zalloc(sizeof(char *) * npmus);
++ if (!evt_pmus)
++ goto out_enomem;
++ }
++
++restart:
++ if (evt_num_known) {
++ evt_list = zalloc(sizeof(char *) * evt_num);
++ if (!evt_list)
++ goto out_enomem;
++ }
++
++ for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
++ for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
++ /* skip invalid cache type */
++ if (!evsel__is_cache_op_valid(type, op))
++ continue;
++
++ for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
++ unsigned int hybrid_supported = 0, j;
++ bool supported;
++
++ __evsel__hw_cache_type_op_res_name(type, op, i, name, sizeof(name));
++ if (event_glob != NULL && !strglobmatch(name, event_glob))
++ continue;
++
++ if (!perf_pmu__has_hybrid()) {
++ if (!is_event_supported(PERF_TYPE_HW_CACHE,
++ type | (op << 8) | (i << 16))) {
++ continue;
++ }
++ } else {
++ perf_pmu__for_each_hybrid_pmu(pmu) {
++ if (!evt_num_known) {
++ evt_num++;
++ continue;
++ }
++
++ supported = is_event_supported(
++ PERF_TYPE_HW_CACHE,
++ type | (op << 8) | (i << 16) |
++ ((__u64)pmu->type << PERF_PMU_TYPE_SHIFT));
++ if (supported) {
++ snprintf(new_name, sizeof(new_name),
++ "%s/%s/", pmu->name, name);
++ evt_pmus[hybrid_supported] =
++ strdup(new_name);
++ hybrid_supported++;
++ }
++ }
++
++ if (hybrid_supported == 0)
++ continue;
++ }
++
++ if (!evt_num_known) {
++ evt_num++;
++ continue;
++ }
++
++ if ((hybrid_supported == 0) ||
++ (hybrid_supported == npmus)) {
++ evt_list[evt_i] = strdup(name);
++ if (npmus > 0) {
++ for (j = 0; j < npmus; j++)
++ zfree(&evt_pmus[j]);
++ }
++ } else {
++ for (j = 0; j < hybrid_supported; j++) {
++ evt_list[evt_i++] = evt_pmus[j];
++ evt_pmus[j] = NULL;
++ }
++ continue;
++ }
++
++ if (evt_list[evt_i] == NULL)
++ goto out_enomem;
++ evt_i++;
++ }
++ }
++ }
++
++ if (!evt_num_known) {
++ evt_num_known = true;
++ goto restart;
++ }
++
++ for (evt_i = 0; evt_i < evt_num; evt_i++) {
++ if (!evt_list[evt_i])
++ break;
++ }
++
++ evt_num = evt_i;
++ qsort(evt_list, evt_num, sizeof(char *), cmp_string);
++ evt_i = 0;
++ while (evt_i < evt_num) {
++ if (name_only) {
++ printf("%s ", evt_list[evt_i++]);
++ continue;
++ }
++ printf(" %-50s [%s]\n", evt_list[evt_i++],
++ event_type_descriptors[PERF_TYPE_HW_CACHE]);
++ }
++ if (evt_num && pager_in_use())
++ printf("\n");
++
++out_free:
++ evt_num = evt_i;
++ for (evt_i = 0; evt_i < evt_num; evt_i++)
++ zfree(&evt_list[evt_i]);
++ zfree(&evt_list);
++
++ for (evt_i = 0; evt_i < npmus; evt_i++)
++ zfree(&evt_pmus[evt_i]);
++ zfree(&evt_pmus);
++ return evt_num;
++
++out_enomem:
++ printf("FATAL: not enough memory to print %s\n",
++ event_type_descriptors[PERF_TYPE_HW_CACHE]);
++ if (evt_list)
++ goto out_free;
++ return evt_num;
++}
++
++static void print_tool_event(const struct event_symbol *syms, const char *event_glob,
++ bool name_only)
++{
++ if (syms->symbol == NULL)
++ return;
++
++ if (event_glob && !(strglobmatch(syms->symbol, event_glob) ||
++ (syms->alias && strglobmatch(syms->alias, event_glob))))
++ return;
++
++ if (name_only)
++ printf("%s ", syms->symbol);
++ else {
++ char name[MAX_NAME_LEN];
++
++ if (syms->alias && strlen(syms->alias))
++ snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias);
++ else
++ strlcpy(name, syms->symbol, MAX_NAME_LEN);
++ printf(" %-50s [%s]\n", name, "Tool event");
++ }
++}
++
++void print_tool_events(const char *event_glob, bool name_only)
++{
++ // Start at 1 because the first enum entry means no tool event.
++ for (int i = 1; i < PERF_TOOL_MAX; ++i)
++ print_tool_event(event_symbols_tool + i, event_glob, name_only);
++
++ if (pager_in_use())
++ printf("\n");
++}
++
++void print_symbol_events(const char *event_glob, unsigned int type,
++ struct event_symbol *syms, unsigned int max,
++ bool name_only)
++{
++ unsigned int i, evt_i = 0, evt_num = 0;
++ char name[MAX_NAME_LEN];
++ char **evt_list = NULL;
++ bool evt_num_known = false;
++
++restart:
++ if (evt_num_known) {
++ evt_list = zalloc(sizeof(char *) * evt_num);
++ if (!evt_list)
++ goto out_enomem;
++ syms -= max;
++ }
++
++ for (i = 0; i < max; i++, syms++) {
++ /*
++ * New attr.config still not supported here, the latest
++ * example was PERF_COUNT_SW_CGROUP_SWITCHES
++ */
++ if (syms->symbol == NULL)
++ continue;
++
++ if (event_glob != NULL && !(strglobmatch(syms->symbol, event_glob) ||
++ (syms->alias && strglobmatch(syms->alias, event_glob))))
++ continue;
++
++ if (!is_event_supported(type, i))
++ continue;
++
++ if (!evt_num_known) {
++ evt_num++;
++ continue;
++ }
++
++ if (!name_only && strlen(syms->alias))
++ snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias);
++ else
++ strlcpy(name, syms->symbol, MAX_NAME_LEN);
++
++ evt_list[evt_i] = strdup(name);
++ if (evt_list[evt_i] == NULL)
++ goto out_enomem;
++ evt_i++;
++ }
++
++ if (!evt_num_known) {
++ evt_num_known = true;
++ goto restart;
++ }
++ qsort(evt_list, evt_num, sizeof(char *), cmp_string);
++ evt_i = 0;
++ while (evt_i < evt_num) {
++ if (name_only) {
++ printf("%s ", evt_list[evt_i++]);
++ continue;
++ }
++ printf(" %-50s [%s]\n", evt_list[evt_i++], event_type_descriptors[type]);
++ }
++ if (evt_num && pager_in_use())
++ printf("\n");
++
++out_free:
++ evt_num = evt_i;
++ for (evt_i = 0; evt_i < evt_num; evt_i++)
++ zfree(&evt_list[evt_i]);
++ zfree(&evt_list);
++ return;
++
++out_enomem:
++ printf("FATAL: not enough memory to print %s\n", event_type_descriptors[type]);
++ if (evt_list)
++ goto out_free;
++}
++
++/*
++ * Print the help text for the event symbols:
++ */
++void print_events(const char *event_glob, bool name_only, bool quiet_flag,
++ bool long_desc, bool details_flag, bool deprecated,
++ const char *pmu_name)
++{
++ print_symbol_events(event_glob, PERF_TYPE_HARDWARE,
++ event_symbols_hw, PERF_COUNT_HW_MAX, name_only);
++
++ print_symbol_events(event_glob, PERF_TYPE_SOFTWARE,
++ event_symbols_sw, PERF_COUNT_SW_MAX, name_only);
++ print_tool_events(event_glob, name_only);
++
++ print_hwcache_events(event_glob, name_only);
++
++ print_pmu_events(event_glob, name_only, quiet_flag, long_desc,
++ details_flag, deprecated, pmu_name);
++
++ if (event_glob != NULL)
++ return;
++
++ if (!name_only) {
++ printf(" %-50s [%s]\n",
++ "rNNN",
++ event_type_descriptors[PERF_TYPE_RAW]);
++ printf(" %-50s [%s]\n",
++ "cpu/t1=v1[,t2=v2,t3 ...]/modifier",
++ event_type_descriptors[PERF_TYPE_RAW]);
++ if (pager_in_use())
++ printf(" (see 'man perf-list' on how to encode it)\n\n");
++
++ printf(" %-50s [%s]\n",
++ "mem:<addr>[/len][:access]",
++ event_type_descriptors[PERF_TYPE_BREAKPOINT]);
++ if (pager_in_use())
++ printf("\n");
++ }
++
++ print_tracepoint_events(NULL, NULL, name_only);
++
++ print_sdt_events(NULL, NULL, name_only);
++
++ metricgroup__print(true, true, NULL, name_only, details_flag,
++ pmu_name);
++
++ print_libpfm_events(name_only, long_desc);
++}
+diff --git a/tools/perf/util/print-events.h b/tools/perf/util/print-events.h
+new file mode 100644
+index 0000000000000..1da9910d83a60
+--- /dev/null
++++ b/tools/perf/util/print-events.h
+@@ -0,0 +1,22 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef __PERF_PRINT_EVENTS_H
++#define __PERF_PRINT_EVENTS_H
++
++#include <stdbool.h>
++
++struct event_symbol;
++
++void print_events(const char *event_glob, bool name_only, bool quiet_flag,
++ bool long_desc, bool details_flag, bool deprecated,
++ const char *pmu_name);
++int print_hwcache_events(const char *event_glob, bool name_only);
++void print_sdt_events(const char *subsys_glob, const char *event_glob,
++ bool name_only);
++void print_symbol_events(const char *event_glob, unsigned int type,
++ struct event_symbol *syms, unsigned int max,
++ bool name_only);
++void print_tool_events(const char *event_glob, bool name_only);
++void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
++ bool name_only);
++
++#endif /* __PERF_PRINT_EVENTS_H */
+diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
+index a65f65d0857e6..892c323b4ac9f 100644
+--- a/tools/perf/util/trace-event-info.c
++++ b/tools/perf/util/trace-event-info.c
+@@ -19,16 +19,24 @@
+ #include <linux/kernel.h>
+ #include <linux/zalloc.h>
+ #include <internal/lib.h> // page_size
++#include <sys/param.h>
+
+ #include "trace-event.h"
++#include "tracepoint.h"
+ #include <api/fs/tracing_path.h>
+ #include "evsel.h"
+ #include "debug.h"
+
+ #define VERSION "0.6"
++#define MAX_EVENT_LENGTH 512
+
+ static int output_fd;
+
++struct tracepoint_path {
++ char *system;
++ char *name;
++ struct tracepoint_path *next;
++};
+
+ int bigendian(void)
+ {
+@@ -400,6 +408,94 @@ put_tracepoints_path(struct tracepoint_path *tps)
+ }
+ }
+
++static struct tracepoint_path *tracepoint_id_to_path(u64 config)
++{
++ struct tracepoint_path *path = NULL;
++ DIR *sys_dir, *evt_dir;
++ struct dirent *sys_dirent, *evt_dirent;
++ char id_buf[24];
++ int fd;
++ u64 id;
++ char evt_path[MAXPATHLEN];
++ char *dir_path;
++
++ sys_dir = tracing_events__opendir();
++ if (!sys_dir)
++ return NULL;
++
++ for_each_subsystem(sys_dir, sys_dirent) {
++ dir_path = get_events_file(sys_dirent->d_name);
++ if (!dir_path)
++ continue;
++ evt_dir = opendir(dir_path);
++ if (!evt_dir)
++ goto next;
++
++ for_each_event(dir_path, evt_dir, evt_dirent) {
++
++ scnprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path,
++ evt_dirent->d_name);
++ fd = open(evt_path, O_RDONLY);
++ if (fd < 0)
++ continue;
++ if (read(fd, id_buf, sizeof(id_buf)) < 0) {
++ close(fd);
++ continue;
++ }
++ close(fd);
++ id = atoll(id_buf);
++ if (id == config) {
++ put_events_file(dir_path);
++ closedir(evt_dir);
++ closedir(sys_dir);
++ path = zalloc(sizeof(*path));
++ if (!path)
++ return NULL;
++ if (asprintf(&path->system, "%.*s",
++ MAX_EVENT_LENGTH, sys_dirent->d_name) < 0) {
++ free(path);
++ return NULL;
++ }
++ if (asprintf(&path->name, "%.*s",
++ MAX_EVENT_LENGTH, evt_dirent->d_name) < 0) {
++ zfree(&path->system);
++ free(path);
++ return NULL;
++ }
++ return path;
++ }
++ }
++ closedir(evt_dir);
++next:
++ put_events_file(dir_path);
++ }
++
++ closedir(sys_dir);
++ return NULL;
++}
++
++static struct tracepoint_path *tracepoint_name_to_path(const char *name)
++{
++ struct tracepoint_path *path = zalloc(sizeof(*path));
++ char *str = strchr(name, ':');
++
++ if (path == NULL || str == NULL) {
++ free(path);
++ return NULL;
++ }
++
++ path->system = strndup(name, str - name);
++ path->name = strdup(str+1);
++
++ if (path->system == NULL || path->name == NULL) {
++ zfree(&path->system);
++ zfree(&path->name);
++ zfree(&path);
++ }
++
++ return path;
++}
++
+ static struct tracepoint_path *
+ get_tracepoints_path(struct list_head *pattrs)
+ {
+diff --git a/tools/perf/util/tracepoint.c b/tools/perf/util/tracepoint.c
+new file mode 100644
+index 0000000000000..89ef56c433110
+--- /dev/null
++++ b/tools/perf/util/tracepoint.c
+@@ -0,0 +1,63 @@
++// SPDX-License-Identifier: GPL-2.0
++#include "tracepoint.h"
++
++#include <errno.h>
++#include <fcntl.h>
++#include <stdio.h>
++#include <sys/param.h>
++#include <unistd.h>
++
++#include <api/fs/tracing_path.h>
++
++int tp_event_has_id(const char *dir_path, struct dirent *evt_dir)
++{
++ char evt_path[MAXPATHLEN];
++ int fd;
++
++ snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, evt_dir->d_name);
++ fd = open(evt_path, O_RDONLY);
++ if (fd < 0)
++ return -EINVAL;
++ close(fd);
++
++ return 0;
++}
++
++/*
++ * Check whether event is in <debugfs_mount_point>/tracing/events
++ */
++int is_valid_tracepoint(const char *event_string)
++{
++ DIR *sys_dir, *evt_dir;
++ struct dirent *sys_dirent, *evt_dirent;
++ char evt_path[MAXPATHLEN];
++ char *dir_path;
++
++ sys_dir = tracing_events__opendir();
++ if (!sys_dir)
++ return 0;
++
++ for_each_subsystem(sys_dir, sys_dirent) {
++ dir_path = get_events_file(sys_dirent->d_name);
++ if (!dir_path)
++ continue;
++ evt_dir = opendir(dir_path);
++ if (!evt_dir)
++ goto next;
++
++ for_each_event(dir_path, evt_dir, evt_dirent) {
++ snprintf(evt_path, MAXPATHLEN, "%s:%s",
++ sys_dirent->d_name, evt_dirent->d_name);
++ if (!strcmp(evt_path, event_string)) {
++ closedir(evt_dir);
++ closedir(sys_dir);
++ return 1;
++ }
++ }
++ closedir(evt_dir);
++next:
++ put_events_file(dir_path);
++ }
++ closedir(sys_dir);
++ return 0;
++}
+diff --git a/tools/perf/util/tracepoint.h b/tools/perf/util/tracepoint.h
+new file mode 100644
+index 0000000000000..c4a110fe87d7b
+--- /dev/null
++++ b/tools/perf/util/tracepoint.h
+@@ -0,0 +1,25 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef __PERF_TRACEPOINT_H
++#define __PERF_TRACEPOINT_H
++
++#include <dirent.h>
++#include <string.h>
++
++int tp_event_has_id(const char *dir_path, struct dirent *evt_dir);
++
++#define for_each_event(dir_path, evt_dir, evt_dirent) \
++ while ((evt_dirent = readdir(evt_dir)) != NULL) \
++ if (evt_dirent->d_type == DT_DIR && \
++ (strcmp(evt_dirent->d_name, ".")) && \
++ (strcmp(evt_dirent->d_name, "..")) && \
++ (!tp_event_has_id(dir_path, evt_dirent)))
++
++#define for_each_subsystem(sys_dir, sys_dirent) \
++ while ((sys_dirent = readdir(sys_dir)) != NULL) \
++ if (sys_dirent->d_type == DT_DIR && \
++ (strcmp(sys_dirent->d_name, ".")) && \
++ (strcmp(sys_dirent->d_name, "..")))
++
++int is_valid_tracepoint(const char *event_string);
++
++#endif /* __PERF_TRACEPOINT_H */
+diff --git a/tools/testing/selftests/net/reuseport_bpf.c b/tools/testing/selftests/net/reuseport_bpf.c
+index 072d709c96b48..65aea27d761ca 100644
+--- a/tools/testing/selftests/net/reuseport_bpf.c
++++ b/tools/testing/selftests/net/reuseport_bpf.c
+@@ -328,7 +328,7 @@ static void test_extra_filter(const struct test_params p)
+ if (bind(fd1, addr, sockaddr_size()))
+ error(1, errno, "failed to bind recv socket 1");
+
+- if (!bind(fd2, addr, sockaddr_size()) && errno != EADDRINUSE)
++ if (!bind(fd2, addr, sockaddr_size()) || errno != EADDRINUSE)
+ error(1, errno, "bind socket 2 should fail with EADDRINUSE");
+
+ free(addr);