The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [RFCv2 PATCH 4/6] x86/tdx: Implement arch_unaccept_memory()
From: Zhenzhong Duan @ 2026-06-23 10:17 UTC (permalink / raw)
  To: marcandre.lureau, david, kas, rick.p.edgecombe, prsampat,
	pbonzini, mst, peterx, chenyi.qiang, elena.reshetova,
	michael.roth, ackerleytng
  Cc: linux-kernel, linux-coco, virtualization, x86, yilun.xu,
	xiaoyao.li, chao.p.peng
In-Reply-To: <20260623101739.79695-1-zhenzhong.duan@intel.com>

During memory hot-unplug, if the VMM does not punch hole the memory, the
memory stays in "accepted" state. Consequently, subsequent re-acceptance
of that same memory during a re-plug operation will trigger re-accept
failure. To guard this, a confidential guest must maintain control of
the memory state explicitly, e.g., setting memory to "unaccepted" state
during unplug.

In the context of TDX, the "unaccepted" state maps to the PENDING state,
while the "accepted" state maps to the MAPPED state. Implement
arch_unaccept_memory() for TDX guest via the TDG.MEM.PAGE.RELEASE TDCALL.
It uses 1G/2M/4K page size fallbacks and rolls back on partial failure. A
failure during this rollback step indicates severe corruption of the TDX
module state and triggers a kernel panic.

Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
---
 arch/x86/include/asm/shared/tdx.h        |   2 +
 arch/x86/include/asm/tdx.h               |   2 +
 arch/x86/include/asm/unaccepted_memory.h |  11 +++
 arch/x86/coco/tdx/tdx.c                  | 120 +++++++++++++++++++++++
 4 files changed, 135 insertions(+)

diff --git a/arch/x86/include/asm/shared/tdx.h b/arch/x86/include/asm/shared/tdx.h
index 049638e3da74..910ec1e57528 100644
--- a/arch/x86/include/asm/shared/tdx.h
+++ b/arch/x86/include/asm/shared/tdx.h
@@ -19,6 +19,7 @@
 #define TDG_MEM_PAGE_ACCEPT		6
 #define TDG_VM_RD			7
 #define TDG_VM_WR			8
+#define TDG_MEM_PAGE_RELEASE		30
 
 /* TDX TD attributes */
 #define TDX_TD_ATTR_DEBUG_BIT		0
@@ -54,6 +55,7 @@
 
 /* TDCS_CONFIG_FLAGS bits */
 #define TDCS_CONFIG_FLEXIBLE_PENDING_VE	BIT_ULL(1)
+#define TDCS_CONFIG_PAGE_RELEASE	BIT_ULL(6)
 
 /* TDCS_TD_CTLS bits */
 #define TD_CTLS_PENDING_VE_DISABLE_BIT	0
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index a149740b24e8..8608d33a7db6 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -72,6 +72,8 @@ int tdx_mcall_extend_rtmr(u8 index, u8 *data);
 
 u64 tdx_hcall_get_quote(u8 *buf, size_t size);
 
+bool tdx_unaccept_memory(phys_addr_t start, phys_addr_t end);
+
 void __init tdx_dump_attributes(u64 td_attr);
 void __init tdx_dump_td_ctls(u64 td_ctls);
 
diff --git a/arch/x86/include/asm/unaccepted_memory.h b/arch/x86/include/asm/unaccepted_memory.h
index f5937e9866ac..9fd9411d2c44 100644
--- a/arch/x86/include/asm/unaccepted_memory.h
+++ b/arch/x86/include/asm/unaccepted_memory.h
@@ -18,6 +18,17 @@ static inline void arch_accept_memory(phys_addr_t start, phys_addr_t end)
 	}
 }
 
+static inline void arch_unaccept_memory(phys_addr_t start, phys_addr_t end)
+{
+	/* Platform-specific memory-unacceptance call goes here */
+	if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST)) {
+		if (!tdx_unaccept_memory(start, end))
+			panic("TDX: Failed to unaccept memory\n");
+	} else {
+		panic("Cannot unaccept memory: unknown platform\n");
+	}
+}
+
 static inline struct efi_unaccepted_memory *efi_get_unaccepted_table(void)
 {
 	if (efi.unaccepted == EFI_INVALID_TABLE_ADDR)
diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c
index 186915a17c50..1bab8f4687bf 100644
--- a/arch/x86/coco/tdx/tdx.c
+++ b/arch/x86/coco/tdx/tdx.c
@@ -326,6 +326,124 @@ static void reduce_unnecessary_ve(void)
 	enable_cpu_topology_enumeration();
 }
 
+static bool tdx_page_release_supported;
+
+static void tdx_detect_page_release_support(void)
+{
+	u64 config = 0;
+
+	tdg_vm_rd(TDCS_CONFIG_FLAGS, &config);
+
+	tdx_page_release_supported = !!(config & TDCS_CONFIG_PAGE_RELEASE);
+}
+
+static unsigned long try_release_one(phys_addr_t start, unsigned long len,
+				     enum pg_level pg_level)
+{
+	unsigned long release_size = page_level_size(pg_level);
+	struct tdx_module_args args = {};
+	u8 page_size;
+	u64 ret;
+
+	if (!IS_ALIGNED(start, release_size))
+		return 0;
+
+	if (len < release_size)
+		return 0;
+
+	/*
+	 * Pass the page physical address to TDX module to release the
+	 * private page and to put it in PENDING state.
+	 *
+	 * Encode page size in RCX[2:0] using TDX_PS_*
+	 */
+	switch (pg_level) {
+	case PG_LEVEL_4K:
+		page_size = TDX_PS_4K;
+		break;
+	case PG_LEVEL_2M:
+		page_size = TDX_PS_2M;
+		break;
+	case PG_LEVEL_1G:
+		page_size = TDX_PS_1G;
+		break;
+	default:
+		return 0;
+	}
+
+	args.rcx = start | page_size;
+	ret = __tdcall(TDG_MEM_PAGE_RELEASE, &args);
+	if (ret)
+		return 0;
+
+	return release_size;
+}
+
+static bool tdx_release_memory(phys_addr_t start, phys_addr_t end, phys_addr_t *cur)
+{
+	*cur = start;
+
+	while (*cur < end) {
+		unsigned long len = end - *cur;
+		unsigned long release_size;
+
+		/*
+		 * Try larger release first. It speeds up process by cutting
+		 * number of hypercalls (if successful).
+		 */
+
+		release_size = try_release_one(*cur, len, PG_LEVEL_1G);
+		if (!release_size)
+			release_size = try_release_one(*cur, len, PG_LEVEL_2M);
+		if (!release_size)
+			release_size = try_release_one(*cur, len, PG_LEVEL_4K);
+		if (!release_size)
+			return false;
+		*cur += release_size;
+	}
+
+	return true;
+}
+
+/**
+ * Release private memory and put it in PENDING state.
+ *
+ * @start: Physical start address of memory range to release
+ * @end:   Physical end address of memory range to release
+ *
+ * Uses TDG.MEM.PAGE.RELEASE TDCALL to transition private pages back to
+ * PENDING state. If PAGE_RELEASE is not supported by the TDX
+ * configuration, returns true (success) as no action is needed.
+ *
+ * On partial failure, automatically re-accepts any successfully released
+ * pages to restore consistent memory state. Re-acceptance failure is
+ * treated as a fatal error since it indicates severe TDX module issues.
+ *
+ * Returns: true on success, false on failure
+ */
+bool tdx_unaccept_memory(phys_addr_t start, phys_addr_t end)
+{
+	phys_addr_t released = start;
+	bool ret;
+
+	if (!tdx_page_release_supported)
+		return true;
+
+	ret = tdx_release_memory(start, end, &released);
+	if (!ret) {
+		pr_err("Failed to unaccept memory [%pa, %pa)\n", &start, &end);
+		/*
+		 * Re-accept any pages that were successfully released before
+		 * the failure occurred. This should never fail since we're
+		 * just restoring the previous MAPPED state.
+		 */
+		if (!tdx_accept_memory(start, released))
+			panic("%s: Failed to re-accept memory\n", __func__);
+	}
+
+	return ret;
+}
+
 static void tdx_setup(u64 *cc_mask)
 {
 	struct tdx_module_args args = {};
@@ -359,6 +477,8 @@ static void tdx_setup(u64 *cc_mask)
 	disable_sept_ve(td_attr);
 
 	reduce_unnecessary_ve();
+
+	tdx_detect_page_release_support();
 }
 
 /*
-- 
2.52.0


^ permalink raw reply related

* [RFCv2 PATCH 5/6] mm/memory_hotplug: Support ACPI hotplug/unplug for coco guest
From: Zhenzhong Duan @ 2026-06-23 10:17 UTC (permalink / raw)
  To: marcandre.lureau, david, kas, rick.p.edgecombe, prsampat,
	pbonzini, mst, peterx, chenyi.qiang, elena.reshetova,
	michael.roth, ackerleytng
  Cc: linux-kernel, linux-coco, virtualization, x86, yilun.xu,
	xiaoyao.li, chao.p.peng
In-Reply-To: <20260623101739.79695-1-zhenzhong.duan@intel.com>

Integrate coco memory management operations into the core memory hotplug
subsystem to handle the lifecycle of hotplug memory.

In add_memory_resource(), invoke coco_set_plugged_bitmap(..., true) to mark
memory plugged before adding the memory block, because self hosted memmap
initialization needs their plugged bits set before acceptance. There is no
explicit call to accept_memory() for normal pages, because they can be
lazily accepted by the core memory management subsystem after the memory
block is onlined.

In try_remove_memory(), before finalizing the physical removal of the
memory blocks, invoke unaccept_memory(). This allows the guest to take
direct control of its own memory state and release the pages itself,
eliminating the dependency on the VMM to implicitly hole-punch the memory.
It loops through the targeted ranges using find_next_andnot_bit(), matching
pages that are marked plugged and accepted, and releases them back to the
host. Following the unacceptance step, clear the ranges from the plugged
bitmap.

These operations guarantee that both the unaccepted and plugged tracking
states stay completely synchronized with the actual dynamic memory
configurations of the guest.

Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
---
 include/linux/mm.h                       | 11 +++
 drivers/firmware/efi/unaccepted_memory.c | 94 ++++++++++++++++++++++++
 mm/memory_hotplug.c                      | 16 ++++
 3 files changed, 121 insertions(+)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index fc2acedf0b76..4c094038872a 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -5105,6 +5105,8 @@ int set_anon_vma_name(unsigned long addr, unsigned long size,
 
 bool range_contains_unaccepted_memory(phys_addr_t start, unsigned long size);
 void accept_memory(phys_addr_t start, unsigned long size);
+void unaccept_memory(phys_addr_t start, unsigned long size);
+int coco_set_plugged_bitmap(phys_addr_t start, unsigned long size, bool set);
 
 #else
 
@@ -5118,6 +5120,15 @@ static inline void accept_memory(phys_addr_t start, unsigned long size)
 {
 }
 
+static inline void unaccept_memory(phys_addr_t start, unsigned long size)
+{
+}
+
+static inline int coco_set_plugged_bitmap(phys_addr_t start, unsigned long size, bool set)
+{
+	return 0;
+}
+
 #endif
 
 static inline bool pfn_is_unaccepted_memory(unsigned long pfn)
diff --git a/drivers/firmware/efi/unaccepted_memory.c b/drivers/firmware/efi/unaccepted_memory.c
index c290b16c5142..f35f7016af53 100644
--- a/drivers/firmware/efi/unaccepted_memory.c
+++ b/drivers/firmware/efi/unaccepted_memory.c
@@ -233,6 +233,100 @@ bool range_contains_unaccepted_memory(phys_addr_t start, unsigned long size)
 	return ret;
 }
 
+static int coco_hotplug_range_check(struct efi_unaccepted_memory *unaccepted,
+				    phys_addr_t start, unsigned long size)
+{
+	u64 unit_size = unaccepted->unit_size;
+	u64 phys_base = unaccepted->phys_base;
+	u64 phys_end = phys_base + unaccepted->size * unit_size * BITS_PER_BYTE;
+
+	if (!IS_ALIGNED(start | size, unit_size))
+		return -EINVAL;
+
+	if (start < phys_base || start + size > phys_end)
+		return -EINVAL;
+
+	return 0;
+}
+
+/* Only used by hotplug memory, we don't unaccept static memory */
+void unaccept_memory(phys_addr_t start, unsigned long size)
+{
+	unsigned long range_start, range_end, bitmap_size, flags;
+	struct efi_unaccepted_memory *unaccepted;
+	void *plugged_bitmap;
+	u64 unit_size;
+
+	unaccepted = efi_get_unaccepted_table();
+	if (!unaccepted)
+		return;
+
+	if (WARN_ON(coco_hotplug_range_check(unaccepted, start, size)))
+		return;
+
+	unit_size = unaccepted->unit_size;
+	range_start = (start - unaccepted->phys_base) / unit_size;
+	bitmap_size = range_start + size / unit_size;
+	plugged_bitmap = plugged_bitmap_of(unaccepted);
+
+	spin_lock_irqsave(&unaccepted_memory_lock, flags);
+	for (; range_start < bitmap_size; range_start = range_end) {
+		unsigned long phys_start, phys_end;
+		unsigned long unaccepted_one, plugged_zero;
+
+		range_start = find_next_andnot_bit(plugged_bitmap, unaccepted->bitmap,
+						   bitmap_size, range_start);
+
+		if (range_start >= bitmap_size)
+			break;
+
+		unaccepted_one = find_next_bit(unaccepted->bitmap, bitmap_size, range_start);
+		plugged_zero = find_next_zero_bit(plugged_bitmap, bitmap_size, range_start);
+		range_end = min(unaccepted_one, plugged_zero);
+
+		phys_start = range_start * unit_size + unaccepted->phys_base;
+		phys_end = range_end * unit_size + unaccepted->phys_base;
+
+		arch_unaccept_memory(phys_start, phys_end);
+		bitmap_set(unaccepted->bitmap, range_start, range_end - range_start);
+	}
+	spin_unlock_irqrestore(&unaccepted_memory_lock, flags);
+}
+
+/*
+ * Only used by hotplug memory, plugged bits of static memory are handled
+ * in process_unaccepted_memory()
+ */
+int coco_set_plugged_bitmap(phys_addr_t start, unsigned long size, bool set)
+{
+	struct efi_unaccepted_memory *unaccepted;
+	unsigned long range_start, flags;
+	void *plugged_bitmap;
+	u64 unit_size;
+	int ret;
+
+	unaccepted = efi_get_unaccepted_table();
+	if (!unaccepted)
+		return 0;
+
+	ret = coco_hotplug_range_check(unaccepted, start, size);
+	if (ret)
+		return ret;
+
+	unit_size = unaccepted->unit_size;
+	range_start = (start - unaccepted->phys_base) / unit_size;
+	plugged_bitmap = plugged_bitmap_of(unaccepted);
+
+	spin_lock_irqsave(&unaccepted_memory_lock, flags);
+	if (set)
+		bitmap_set(plugged_bitmap, range_start, size / unit_size);
+	else
+		bitmap_clear(plugged_bitmap, range_start, size / unit_size);
+	spin_unlock_irqrestore(&unaccepted_memory_lock, flags);
+
+	return 0;
+}
+
 #ifdef CONFIG_PROC_VMCORE
 static bool unaccepted_memory_vmcore_pfn_is_ram(struct vmcore_cb *cb,
 						unsigned long pfn)
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 40c7915dabe0..2f71514a0616 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1429,6 +1429,8 @@ static void remove_memory_blocks_and_altmaps(u64 start, u64 size)
 
 		arch_remove_memory(cur_start, memblock_size, altmap);
 
+		unaccept_memory(cur_start, PFN_PHYS(altmap->free));
+
 		/* Verify that all vmemmap pages have actually been freed. */
 		WARN(altmap->alloc, "Altmap not fully unmapped");
 		kfree(altmap);
@@ -1459,9 +1461,13 @@ static int create_altmaps_and_memory_blocks(int nid, struct memory_group *group,
 			goto out;
 		}
 
+		/* Accept self hosted memmap array before access it */
+		accept_memory(cur_start, PFN_PHYS(mhp_altmap.free));
+
 		/* call arch's memory hotadd */
 		ret = arch_add_memory(nid, cur_start, memblock_size, &params);
 		if (ret < 0) {
+			unaccept_memory(cur_start, PFN_PHYS(mhp_altmap.free));
 			kfree(params.altmap);
 			goto out;
 		}
@@ -1471,6 +1477,7 @@ static int create_altmaps_and_memory_blocks(int nid, struct memory_group *group,
 						  params.altmap, group);
 		if (ret) {
 			arch_remove_memory(cur_start, memblock_size, NULL);
+			unaccept_memory(cur_start, PFN_PHYS(mhp_altmap.free));
 			kfree(params.altmap);
 			goto out;
 		}
@@ -1540,6 +1547,10 @@ int add_memory_resource(int nid, struct resource *res, mhp_t mhp_flags)
 		new_node = true;
 	}
 
+	ret = coco_set_plugged_bitmap(start, size, true);
+	if (ret)
+		goto error_offline_node;
+
 	/*
 	 * Self hosted memmap array
 	 */
@@ -1584,6 +1595,8 @@ int add_memory_resource(int nid, struct resource *res, mhp_t mhp_flags)
 
 	return ret;
 error:
+	WARN_ON(coco_set_plugged_bitmap(start, size, false));
+error_offline_node:
 	if (new_node) {
 		node_set_offline(nid);
 		unregister_node(nid);
@@ -2282,6 +2295,9 @@ static int try_remove_memory(u64 start, u64 size)
 	if (nid != NUMA_NO_NODE)
 		try_offline_node(nid);
 
+	unaccept_memory(start, size);
+	WARN_ON(coco_set_plugged_bitmap(start, size, false));
+
 	mem_hotplug_done();
 	return 0;
 }
-- 
2.52.0


^ permalink raw reply related

* [RFCv2 PATCH 6/6] virtio-mem: Support memory hotplug/unplug for coco guest
From: Zhenzhong Duan @ 2026-06-23 10:17 UTC (permalink / raw)
  To: marcandre.lureau, david, kas, rick.p.edgecombe, prsampat,
	pbonzini, mst, peterx, chenyi.qiang, elena.reshetova,
	michael.roth, ackerleytng
  Cc: linux-kernel, linux-coco, virtualization, x86, yilun.xu,
	xiaoyao.li, chao.p.peng
In-Reply-To: <20260623101739.79695-1-zhenzhong.duan@intel.com>

Integrate coco memory management operations into the virtio-mem driver to
manage the state of hotplug memory.

In virtio_mem_send_plug_request(), once the host hypervisor acknowledges a
plug request, invoke coco_set_plugged_bitmap() to set the corresponding
bits in the plugged bitmap. Conversely, in virtio_mem_send_unplug_request()
and virtio_mem_send_unplug_all_request(), call unaccept_memory() to let the
guest autonomously transition the target private pages back to "unaccepted"
state before asking the VMM to unplug them. After the VMM acknowledges the
unplug request, clear the ranges from the plugged bitmap.

Note that memory block hotplug/unplug also sets or clears the plugged
bitmap at memory block granularity. While doing this at device block
granularity here creates a slight redundancy, it is completely harmless.

Additionally, update virtio_mem_fake_online() to explicitly invoke
accept_memory() when transitioning memory out of the fake-offline state and
back into service. This ensures that any pages returning to the buddy
system are cleanly accepted by the guest architecture before they are freed
back into the allocator via free_contig_range().

Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
---
 drivers/virtio/virtio_mem.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/virtio/virtio_mem.c b/drivers/virtio/virtio_mem.c
index 48051e9e98ab..9f6e53df8caf 100644
--- a/drivers/virtio/virtio_mem.c
+++ b/drivers/virtio/virtio_mem.c
@@ -1211,6 +1211,7 @@ static void virtio_mem_fake_online(unsigned long pfn, unsigned long nr_pages)
 			generic_online_page(page, order);
 		} else {
 			virtio_mem_clear_fake_offline(pfn + i, 1 << order, true);
+			accept_memory(page_to_phys(page), PAGE_SIZE << order);
 			free_contig_range(pfn + i, 1 << order);
 			adjust_managed_page_count(page, 1 << order);
 		}
@@ -1436,6 +1437,7 @@ static int virtio_mem_send_plug_request(struct virtio_mem *vm, uint64_t addr,
 	switch (virtio_mem_send_request(vm, &req)) {
 	case VIRTIO_MEM_RESP_ACK:
 		vm->plugged_size += size;
+		WARN_ON(coco_set_plugged_bitmap(addr, size, true));
 		return 0;
 	case VIRTIO_MEM_RESP_NACK:
 		rc = -EAGAIN;
@@ -1471,9 +1473,12 @@ static int virtio_mem_send_unplug_request(struct virtio_mem *vm, uint64_t addr,
 	dev_dbg(&vm->vdev->dev, "unplugging memory: 0x%llx - 0x%llx\n", addr,
 		addr + size - 1);
 
+	unaccept_memory(addr, size);
+
 	switch (virtio_mem_send_request(vm, &req)) {
 	case VIRTIO_MEM_RESP_ACK:
 		vm->plugged_size -= size;
+		WARN_ON(coco_set_plugged_bitmap(addr, size, false));
 		return 0;
 	case VIRTIO_MEM_RESP_BUSY:
 		rc = -ETXTBSY;
@@ -1498,10 +1503,13 @@ static int virtio_mem_send_unplug_all_request(struct virtio_mem *vm)
 
 	dev_dbg(&vm->vdev->dev, "unplugging all memory");
 
+	unaccept_memory(vm->addr, vm->region_size);
+
 	switch (virtio_mem_send_request(vm, &req)) {
 	case VIRTIO_MEM_RESP_ACK:
 		vm->unplug_all_required = false;
 		vm->plugged_size = 0;
+		WARN_ON(coco_set_plugged_bitmap(vm->addr, vm->region_size, false));
 		/* usable region might have shrunk */
 		atomic_set(&vm->config_changed, 1);
 		return 0;
-- 
2.52.0


^ permalink raw reply related

* [PATCH v2 3/5] ASoC: max98373: Add back local call to sdw_show_ping_status()
From: Charles Keepax @ 2026-06-23 10:18 UTC (permalink / raw)
  To: broonie
  Cc: vkoul, arnd, lgirdwood, pierre-louis.bossart, yung-chuan.liao,
	peter.ujfalusi, oder_chiou, jack.yu, shumingf, niranjan.hy,
	shenghao-ding, kevin-lu, baojun.xu, sen, zhangyi, linux-sound,
	linux-kernel, patches
In-Reply-To: <20260623101814.24044-1-ckeepax@opensource.cirrus.com>

As the core no longer calls this debug helper add it back to the drivers
that originally called it.

Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---

No changes since v1.

 sound/soc/codecs/max98373-sdw.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c
index 6829fa07c9ecb..7a42052dc0516 100644
--- a/sound/soc/codecs/max98373-sdw.c
+++ b/sound/soc/codecs/max98373-sdw.c
@@ -272,8 +272,10 @@ static int max98373_resume(struct device *dev)
 		return 0;
 
 	ret = sdw_slave_wait_for_init(slave, MAX98373_PROBE_TIMEOUT);
-	if (ret)
+	if (ret) {
+		sdw_show_ping_status(slave->bus, true);
 		return ret;
+	}
 
 	regcache_cache_only(max98373->regmap, false);
 	regcache_sync(max98373->regmap);
-- 
2.47.3


^ permalink raw reply related

* [PATCH v2 0/5] Fix SoundWire randconfig issues
From: Charles Keepax @ 2026-06-23 10:18 UTC (permalink / raw)
  To: broonie
  Cc: vkoul, arnd, lgirdwood, pierre-louis.bossart, yung-chuan.liao,
	peter.ujfalusi, oder_chiou, jack.yu, shumingf, niranjan.hy,
	shenghao-ding, kevin-lu, baojun.xu, sen, zhangyi, linux-sound,
	linux-kernel, patches

Moving all the waiting for soundwire devices to enumerate into the core
code [1] has caused some randconfig issues. This is the second attempt
to fix this after there were some short coming in [2].

Sorry for sending during the merge window, but people are keen to see
a solution posted.

Thanks,
Charles

[1] https://lore.kernel.org/linux-sound/20260608102714.2503120-1-ckeepax@opensource.cirrus.com/
[2] https://lore.kernel.org/lkml/20260615150523.4006982-1-ckeepax@opensource.cirrus.com/

Changes since v1:
 - Add include of jiffies.h

Charles Keepax (5):
  soundwire: Move wait for initialisation helper to header
  ASoC: es9356: Add back local call to sdw_show_ping_status()
  ASoC: max98373: Add back local call to sdw_show_ping_status()
  ASoC: ti: Add back local call to sdw_show_ping_status()
  ASoC: realtek: Add back local call to sdw_show_ping_status()

 drivers/soundwire/bus.c            | 28 ----------------------
 include/linux/soundwire/sdw.h      | 38 +++++++++++++++++++++++-------
 sound/soc/codecs/es9356.c          |  4 +++-
 sound/soc/codecs/max98373-sdw.c    |  4 +++-
 sound/soc/codecs/rt1017-sdca-sdw.c |  4 +++-
 sound/soc/codecs/rt1308-sdw.c      |  4 +++-
 sound/soc/codecs/rt1316-sdw.c      |  4 +++-
 sound/soc/codecs/rt5682-sdw.c      |  4 +++-
 sound/soc/codecs/rt700-sdw.c       |  4 +++-
 sound/soc/codecs/rt711-sdca-sdw.c  |  4 +++-
 sound/soc/codecs/rt712-sdca-dmic.c |  4 +++-
 sound/soc/codecs/rt712-sdca-sdw.c  |  4 +++-
 sound/soc/codecs/rt715-sdca-sdw.c  |  4 +++-
 sound/soc/codecs/rt715-sdw.c       |  4 +++-
 sound/soc/codecs/rt721-sdca-sdw.c  |  4 +++-
 sound/soc/codecs/rt722-sdca-sdw.c  |  4 +++-
 sound/soc/codecs/tac5xx2-sdw.c     |  4 +++-
 sound/soc/codecs/tas2783-sdw.c     |  4 +++-
 18 files changed, 78 insertions(+), 52 deletions(-)

-- 
2.47.3


^ permalink raw reply

* [PATCH v2 2/5] ASoC: es9356: Add back local call to sdw_show_ping_status()
From: Charles Keepax @ 2026-06-23 10:18 UTC (permalink / raw)
  To: broonie
  Cc: vkoul, arnd, lgirdwood, pierre-louis.bossart, yung-chuan.liao,
	peter.ujfalusi, oder_chiou, jack.yu, shumingf, niranjan.hy,
	shenghao-ding, kevin-lu, baojun.xu, sen, zhangyi, linux-sound,
	linux-kernel, patches
In-Reply-To: <20260623101814.24044-1-ckeepax@opensource.cirrus.com>

As the core no longer calls this debug helper add it back to the drivers
that originally called it.

Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---

No changes since v1.

 sound/soc/codecs/es9356.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/sound/soc/codecs/es9356.c b/sound/soc/codecs/es9356.c
index 670e918b56a46..8db81d5746240 100644
--- a/sound/soc/codecs/es9356.c
+++ b/sound/soc/codecs/es9356.c
@@ -1111,8 +1111,10 @@ static int es9356_sdca_dev_resume(struct device *dev)
 		es9356->disable_irq = false;
 
 	ret = sdw_slave_wait_for_init(slave, es9356_PROBE_TIMEOUT);
-	if (ret)
+	if (ret) {
+		sdw_show_ping_status(slave->bus, true);
 		return ret;
+	}
 
 	regcache_cache_only(es9356->regmap, false);
 	regcache_sync(es9356->regmap);
-- 
2.47.3


^ permalink raw reply related

* [PATCH v2 4/5] ASoC: ti: Add back local call to sdw_show_ping_status()
From: Charles Keepax @ 2026-06-23 10:18 UTC (permalink / raw)
  To: broonie
  Cc: vkoul, arnd, lgirdwood, pierre-louis.bossart, yung-chuan.liao,
	peter.ujfalusi, oder_chiou, jack.yu, shumingf, niranjan.hy,
	shenghao-ding, kevin-lu, baojun.xu, sen, zhangyi, linux-sound,
	linux-kernel, patches
In-Reply-To: <20260623101814.24044-1-ckeepax@opensource.cirrus.com>

As the core no longer calls this debug helper add it back to the drivers
that originally called it.

Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---

No changes since v1.

 sound/soc/codecs/tac5xx2-sdw.c | 4 +++-
 sound/soc/codecs/tas2783-sdw.c | 4 +++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/sound/soc/codecs/tac5xx2-sdw.c b/sound/soc/codecs/tac5xx2-sdw.c
index bb12cfb6da12b..ace06f5ab58c1 100644
--- a/sound/soc/codecs/tac5xx2-sdw.c
+++ b/sound/soc/codecs/tac5xx2-sdw.c
@@ -1445,8 +1445,10 @@ static s32 tac5xx2_sdca_dev_resume(struct device *dev)
 	}
 
 	ret = sdw_slave_wait_for_init(slave, TAC5XX2_PROBE_TIMEOUT_MS);
-	if (ret)
+	if (ret) {
+		sdw_show_ping_status(slave->bus, true);
 		return ret;
+	}
 
 	regcache_cache_only(tac_dev->regmap, false);
 	regcache_mark_dirty(tac_dev->regmap);
diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c
index 7d70e7e3f24f4..1127ea59b5e4c 100644
--- a/sound/soc/codecs/tas2783-sdw.c
+++ b/sound/soc/codecs/tas2783-sdw.c
@@ -1083,8 +1083,10 @@ static s32 tas2783_sdca_dev_resume(struct device *dev)
 	int ret;
 
 	ret = sdw_slave_wait_for_init(slave, TAS2783_PROBE_TIMEOUT);
-	if (ret)
+	if (ret) {
+		sdw_show_ping_status(slave->bus, true);
 		return ret;
+	}
 
 	regcache_cache_only(tas_dev->regmap, false);
 	regcache_sync(tas_dev->regmap);
-- 
2.47.3


^ permalink raw reply related

* [PATCH v2 1/5] soundwire: Move wait for initialisation helper to header
From: Charles Keepax @ 2026-06-23 10:18 UTC (permalink / raw)
  To: broonie
  Cc: vkoul, arnd, lgirdwood, pierre-louis.bossart, yung-chuan.liao,
	peter.ujfalusi, oder_chiou, jack.yu, shumingf, niranjan.hy,
	shenghao-ding, kevin-lu, baojun.xu, sen, zhangyi, linux-sound,
	linux-kernel, patches
In-Reply-To: <20260623101814.24044-1-ckeepax@opensource.cirrus.com>

As SoundWire devices tend to enumerate on the bus after probe, drivers
frequently need to wait for the device to initialise from common driver
code. The common system is to split drivers into a core module and then
a module for each communication bus. These two facts tend to cause
Kconfig issues, the issue tends to be when SOUNDWIRE=m and DRIVER_I2C=y,
this usually selects DRIVER=y. The driver code then wants to call
sdw_slave_wait_for_init(), but this results in calling a module function
from built in code. A depends on SOUNDWIRE | !SOUNDWIRE could be added to
the end driver but this seems slightly off as it adds a lot of counter
intuitive depends.

A simpler solution is to make sdw_slave_wait_for_init() a static inline
function. As part of doing this add a check for the slave device being
NULL acknowledging that this is likely called from code that is shared
between control buses. It does require dropping the call to
sdw_show_ping_status() but this can be added back in end drivers that
used it originally.

Currently this is causing rand config issues on RT5682 and will soon
also cause similar problems on cs42l43.

Acked-by: Vinod Koul <vkoul@kernel.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---

Changes since v1:
 - Add include of jiffies.h

 drivers/soundwire/bus.c       | 28 --------------------------
 include/linux/soundwire/sdw.h | 38 +++++++++++++++++++++++++++--------
 2 files changed, 30 insertions(+), 36 deletions(-)

diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index b7bdf19ebb42e..fe5316d93fefe 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -1372,34 +1372,6 @@ int sdw_slave_get_current_bank(struct sdw_slave *slave)
 }
 EXPORT_SYMBOL_GPL(sdw_slave_get_current_bank);
 
-/**
- * sdw_slave_wait_for_init - Wait for device initialisation
- * @slave: Pointer to the SoundWire peripheral.
- * @timeout_ms: Timeout in milliseconds.
- *
- * Wait for a peripheral device to enumerate and be initialised by the
- * SoundWire core.
- *
- * Return: Zero on success, and a negative error code on failure.
- */
-int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms)
-{
-	unsigned long time;
-
-	time = wait_for_completion_timeout(&slave->initialization_complete,
-					   msecs_to_jiffies(timeout_ms));
-	if (!time) {
-		dev_err(&slave->dev, "Initialization not complete\n");
-		sdw_show_ping_status(slave->bus, true);
-		return -ETIMEDOUT;
-	}
-
-	slave->unattach_request = 0;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(sdw_slave_wait_for_init);
-
 static int sdw_slave_set_frequency(struct sdw_slave *slave)
 {
 	int scale_index;
diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index a46cbaec59491..b484784e2690d 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -11,6 +11,7 @@
 #include <linux/idr.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
+#include <linux/jiffies.h>
 #include <linux/lockdep_types.h>
 #include <linux/mod_devicetable.h>
 #include <linux/mutex.h>
@@ -1093,8 +1094,6 @@ int sdw_slave_get_current_bank(struct sdw_slave *sdev);
 
 int sdw_slave_get_scale_index(struct sdw_slave *slave, u8 *base);
 
-int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms);
-
 /* messaging and data APIs */
 int sdw_read(struct sdw_slave *slave, u32 addr);
 int sdw_write(struct sdw_slave *slave, u32 addr, u8 value);
@@ -1138,12 +1137,6 @@ static inline int sdw_slave_get_current_bank(struct sdw_slave *sdev)
 	return -EINVAL;
 }
 
-static inline int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms)
-{
-	WARN_ONCE(1, "SoundWire API is disabled");
-	return -EINVAL;
-}
-
 /* messaging and data APIs */
 static inline int sdw_read(struct sdw_slave *slave, u32 addr)
 {
@@ -1207,4 +1200,33 @@ static inline int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u
 
 #endif /* CONFIG_SOUNDWIRE */
 
+/**
+ * sdw_slave_wait_for_init - Wait for device initialisation
+ * @slave: Pointer to the SoundWire peripheral.
+ * @timeout_ms: Timeout in milliseconds.
+ *
+ * Wait for a peripheral device to enumerate and be initialised by the
+ * SoundWire core.
+ *
+ * Return: Zero on success, and a negative error code on failure.
+ */
+static inline int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms)
+{
+	unsigned long time;
+
+	if (!slave)
+		return 0;
+
+	time = wait_for_completion_timeout(&slave->initialization_complete,
+					   msecs_to_jiffies(timeout_ms));
+	if (!time) {
+		dev_err(&slave->dev, "Initialization not complete\n");
+		return -ETIMEDOUT;
+	}
+
+	slave->unattach_request = 0;
+
+	return 0;
+}
+
 #endif /* __SOUNDWIRE_H */
-- 
2.47.3


^ permalink raw reply related

* Re: [PATCH] usb: xhci-pci: Disable 64-bit DMA for VIA VL805
From: Michal Pecio @ 2026-06-23 10:18 UTC (permalink / raw)
  To: Xincheng Zhang
  Cc: Mathias Nyman, Greg Kroah-Hartman, linux-usb, linux-kernel,
	Forest Crossman
In-Reply-To: <20260623-xhci-via-dma-fix-v1-1-3f12c81a1cf8@ultrarisc.com>

On Tue, 23 Jun 2026 15:32:02 +0800, Xincheng Zhang wrote:
> The VIA VL805 XHCI controller (Device ID 0x3483) fails to handle DMA
> addresses correctly when they exceed 0x1000000000 (64GB). On systems
> with large amounts of RAM, this hardware limitation causes device
> failures.
> 
> Add the XHCI_NO_64BIT_SUPPORT quirk to restrict DMA addressing to
> 32-bit, preventing the controller from receiving addresses beyond its
> hardware limit.
> 
> Signed-off-by: Xincheng Zhang <zhangxincheng@ultrarisc.com>

It could make sense to put a fix for this in stable too.

But I don't like this abuse of the quirk. Firstly, it causes
unnecessary bouncing on systems with >4GB RAM and no IOMMU.
I found other drivers that use DMA_BIT_MASK(36) or even weirder
numbers, so it seems that we too could request 64 gigs exactly
with a bit of driver refactoring.

Secondly, it makes the driver pretend that AC64 capability is absent.
Differences go beyond address bits, notably including register width
and whether QWORD or only DWORD writes cane be used. For example, if
we want to improve command abort on AC64 chips using QWORD writes, we
will need to know the true state of this capability, regarless of
whether the chip really implements all 64 address bits or not.

Forest, you have added a number of similar quirks for ASMedia chips.
Do you happen to know what is their real address width? I think it
might prove useful to have this on record.

Regards,
Michal

^ permalink raw reply

* [PATCH v2 5/5] ASoC: realtek: Add back local call to sdw_show_ping_status()
From: Charles Keepax @ 2026-06-23 10:18 UTC (permalink / raw)
  To: broonie
  Cc: vkoul, arnd, lgirdwood, pierre-louis.bossart, yung-chuan.liao,
	peter.ujfalusi, oder_chiou, jack.yu, shumingf, niranjan.hy,
	shenghao-ding, kevin-lu, baojun.xu, sen, zhangyi, linux-sound,
	linux-kernel, patches
In-Reply-To: <20260623101814.24044-1-ckeepax@opensource.cirrus.com>

As the core no longer calls this debug helper add it back to the drivers
that originally called it.

Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---

No changes since v1.

 sound/soc/codecs/rt1017-sdca-sdw.c | 4 +++-
 sound/soc/codecs/rt1308-sdw.c      | 4 +++-
 sound/soc/codecs/rt1316-sdw.c      | 4 +++-
 sound/soc/codecs/rt5682-sdw.c      | 4 +++-
 sound/soc/codecs/rt700-sdw.c       | 4 +++-
 sound/soc/codecs/rt711-sdca-sdw.c  | 4 +++-
 sound/soc/codecs/rt712-sdca-dmic.c | 4 +++-
 sound/soc/codecs/rt712-sdca-sdw.c  | 4 +++-
 sound/soc/codecs/rt715-sdca-sdw.c  | 4 +++-
 sound/soc/codecs/rt715-sdw.c       | 4 +++-
 sound/soc/codecs/rt721-sdca-sdw.c  | 4 +++-
 sound/soc/codecs/rt722-sdca-sdw.c  | 4 +++-
 12 files changed, 36 insertions(+), 12 deletions(-)

diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c
index d62e8a2536767..91d3d43cd9988 100644
--- a/sound/soc/codecs/rt1017-sdca-sdw.c
+++ b/sound/soc/codecs/rt1017-sdca-sdw.c
@@ -779,8 +779,10 @@ static int rt1017_sdca_dev_resume(struct device *dev)
 		return 0;
 
 	ret = sdw_slave_wait_for_init(slave, RT1017_PROBE_TIMEOUT);
-	if (ret)
+	if (ret) {
+		sdw_show_ping_status(slave->bus, true);
 		return ret;
+	}
 
 	regcache_cache_only(rt1017->regmap, false);
 	regcache_sync(rt1017->regmap);
diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c
index 39e06a3a75609..60e5040b6dd9d 100644
--- a/sound/soc/codecs/rt1308-sdw.c
+++ b/sound/soc/codecs/rt1308-sdw.c
@@ -774,8 +774,10 @@ static int rt1308_dev_resume(struct device *dev)
 		return 0;
 
 	ret = sdw_slave_wait_for_init(slave, RT1308_PROBE_TIMEOUT);
-	if (ret)
+	if (ret) {
+		sdw_show_ping_status(slave->bus, true);
 		return ret;
+	}
 
 	regcache_cache_only(rt1308->regmap, false);
 	regcache_sync_region(rt1308->regmap, 0xc000, 0xcfff);
diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c
index 1828fd9d5af6a..5e8eda6a5f7f8 100644
--- a/sound/soc/codecs/rt1316-sdw.c
+++ b/sound/soc/codecs/rt1316-sdw.c
@@ -751,8 +751,10 @@ static int rt1316_dev_resume(struct device *dev)
 		return 0;
 
 	ret = sdw_slave_wait_for_init(slave, RT1316_PROBE_TIMEOUT);
-	if (ret)
+	if (ret) {
+		sdw_show_ping_status(slave->bus, true);
 		return ret;
+	}
 
 	regcache_cache_only(rt1316->regmap, false);
 	regcache_sync(rt1316->regmap);
diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c
index ec2a35a0cacde..dec8c2147d684 100644
--- a/sound/soc/codecs/rt5682-sdw.c
+++ b/sound/soc/codecs/rt5682-sdw.c
@@ -769,8 +769,10 @@ static int rt5682_dev_resume(struct device *dev)
 	}
 
 	ret = sdw_slave_wait_for_init(slave, RT5682_PROBE_TIMEOUT);
-	if (ret)
+	if (ret) {
+		sdw_show_ping_status(slave->bus, true);
 		return ret;
+	}
 
 	regcache_cache_only(rt5682->sdw_regmap, false);
 	regcache_cache_only(rt5682->regmap, false);
diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c
index 30fcca210f051..6bc636c86f427 100644
--- a/sound/soc/codecs/rt700-sdw.c
+++ b/sound/soc/codecs/rt700-sdw.c
@@ -528,8 +528,10 @@ static int rt700_dev_resume(struct device *dev)
 		return 0;
 
 	ret = sdw_slave_wait_for_init(slave, RT700_PROBE_TIMEOUT);
-	if (ret)
+	if (ret) {
+		sdw_show_ping_status(slave->bus, true);
 		return ret;
+	}
 
 	regcache_cache_only(rt700->regmap, false);
 	regcache_sync_region(rt700->regmap, 0x3000, 0x8fff);
diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c
index a8164fc3979ab..461315844ba99 100644
--- a/sound/soc/codecs/rt711-sdca-sdw.c
+++ b/sound/soc/codecs/rt711-sdca-sdw.c
@@ -454,8 +454,10 @@ static int rt711_sdca_dev_resume(struct device *dev)
 	}
 
 	ret = sdw_slave_wait_for_init(slave, RT711_PROBE_TIMEOUT);
-	if (ret)
+	if (ret) {
+		sdw_show_ping_status(slave->bus, true);
 		return ret;
+	}
 
 	regcache_cache_only(rt711->regmap, false);
 	regcache_sync(rt711->regmap);
diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c
index 4c5c2f5ba5edf..8b7d50a80ff98 100644
--- a/sound/soc/codecs/rt712-sdca-dmic.c
+++ b/sound/soc/codecs/rt712-sdca-dmic.c
@@ -911,8 +911,10 @@ static int rt712_sdca_dmic_dev_resume(struct device *dev)
 		return 0;
 
 	ret = sdw_slave_wait_for_init(slave, RT712_PROBE_TIMEOUT);
-	if (ret)
+	if (ret) {
+		sdw_show_ping_status(slave->bus, true);
 		return ret;
+	}
 
 	regcache_cache_only(rt712->regmap, false);
 	regcache_sync(rt712->regmap);
diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c
index 5817321804736..2787524c796e8 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.c
+++ b/sound/soc/codecs/rt712-sdca-sdw.c
@@ -467,8 +467,10 @@ static int rt712_sdca_dev_resume(struct device *dev)
 	}
 
 	ret = sdw_slave_wait_for_init(slave, RT712_PROBE_TIMEOUT);
-	if (ret)
+	if (ret) {
+		sdw_show_ping_status(slave->bus, true);
 		return ret;
+	}
 
 	regcache_cache_only(rt712->regmap, false);
 	regcache_sync(rt712->regmap);
diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c
index 4b9815b5628db..fabd21bbbe5b9 100644
--- a/sound/soc/codecs/rt715-sdca-sdw.c
+++ b/sound/soc/codecs/rt715-sdca-sdw.c
@@ -230,8 +230,10 @@ static int rt715_dev_resume(struct device *dev)
 		return 0;
 
 	ret = sdw_slave_wait_for_init(slave, RT715_PROBE_TIMEOUT);
-	if (ret)
+	if (ret) {
+		sdw_show_ping_status(slave->bus, true);
 		return ret;
+	}
 
 	regcache_cache_only(rt715->regmap, false);
 	regcache_sync_region(rt715->regmap,
diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c
index 7f83a8f1a06e9..a4a3945522e81 100644
--- a/sound/soc/codecs/rt715-sdw.c
+++ b/sound/soc/codecs/rt715-sdw.c
@@ -507,8 +507,10 @@ static int rt715_dev_resume(struct device *dev)
 		return 0;
 
 	ret = sdw_slave_wait_for_init(slave, RT715_PROBE_TIMEOUT);
-	if (ret)
+	if (ret) {
+		sdw_show_ping_status(slave->bus, true);
 		return ret;
+	}
 
 	regcache_cache_only(rt715->regmap, false);
 	regcache_sync_region(rt715->regmap, 0x3000, 0x8fff);
diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c
index 58606209316a4..02df04a0ddad4 100644
--- a/sound/soc/codecs/rt721-sdca-sdw.c
+++ b/sound/soc/codecs/rt721-sdca-sdw.c
@@ -505,8 +505,10 @@ static int rt721_sdca_dev_resume(struct device *dev)
 	}
 
 	ret = sdw_slave_wait_for_init(slave, RT721_PROBE_TIMEOUT);
-	if (ret)
+	if (ret) {
+		sdw_show_ping_status(slave->bus, true);
 		return ret;
+	}
 
 	regcache_cache_only(rt721->regmap, false);
 	regcache_sync(rt721->regmap);
diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c
index 0f76492ff915c..284900933ebf4 100644
--- a/sound/soc/codecs/rt722-sdca-sdw.c
+++ b/sound/soc/codecs/rt722-sdca-sdw.c
@@ -552,8 +552,10 @@ static int rt722_sdca_dev_resume(struct device *dev)
 	}
 
 	ret = sdw_slave_wait_for_init(slave, RT722_PROBE_TIMEOUT);
-	if (ret)
+	if (ret) {
+		sdw_show_ping_status(slave->bus, true);
 		return ret;
+	}
 
 	regcache_cache_only(rt722->regmap, false);
 	regcache_sync(rt722->regmap);
-- 
2.47.3


^ permalink raw reply related

* Re: [PATCH] orangefs: keep the readdir entry size 64-bit in fill_from_part()
From: Christian Brauner @ 2026-06-23 10:18 UTC (permalink / raw)
  To: Mike Marshall, Bryam Vargas
  Cc: linux-fsdevel, linux-kernel, devel, Martin Brandenburg
In-Reply-To: <20260619-b4-disp-50d2bd59-v1-1-ce332969b4a2@proton.me>

On Fri, 19 Jun 2026 04:38:20 -0500, Bryam Vargas wrote:
> orangefs: keep the readdir entry size 64-bit in fill_from_part()

Applied to the vfs.fixes branch of the vfs/vfs.git tree.
Patches in the vfs.fixes branch should appear in linux-next soon.

Please report any outstanding bugs that were missed during review in a
new review to the original patch series allowing us to drop it.

It's encouraged to provide Acked-bys and Reviewed-bys even though the
patch has now been applied. If possible patch trailers will be updated.

Note that commit hashes shown below are subject to change due to rebase,
trailer updates or similar. If in doubt, please check the listed branch.

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git
branch: vfs.fixes

[1/1] orangefs: keep the readdir entry size 64-bit in fill_from_part()
      https://git.kernel.org/vfs/vfs/c/7adc4b46512c


^ permalink raw reply

* Re: [PATCH 1/2] pwm: loongson: Fix low pulse buffer register handling
From: Keguang Zhang @ 2026-06-23 10:18 UTC (permalink / raw)
  To: Uwe Kleine-König; +Cc: Binbin Zhou, linux-pwm, linux-kernel
In-Reply-To: <ajk5jfEGCAj9QXGO@monoceros>

On Mon, Jun 22, 2026 at 9:58 PM Uwe Kleine-König <ukleinek@kernel.org> wrote:
>
> On Sat, Jun 20, 2026 at 04:22:55PM +0800, Keguang Zhang wrote:
> > On Thu, Jun 18, 2026 at 12:04 AM Uwe Kleine-König <ukleinek@kernel.org> wrote:
> > >
> > > On Tue, Jun 16, 2026 at 07:13:17PM +0800, Keguang Zhang via B4 Relay wrote:
> > > > From: Keguang Zhang <keguang.zhang@gmail.com>
> > > >
> > > > The Loongson PWM register at offset 0x4 is documented as the Low
> > > > Pulse Buffer Register, which stores the low pulse width rather than
> > > > the duty cycle.
> > > >
> > > > However, this register was incorrectly defined and treated as a
> > > > duty-cycle register. As a result, the duty cycle and low pulse cycle
> > > > are swapped in the generated PWM waveform.
> > > >
> > > > Program the low pulse (period - duty) into the register and
> > > > adjust pwm_loongson_get_state() accordingly when reconstructing the
> > > > duty cycle.
> > > >
> > > > Also return -ERANGE when the requested period exceeds the hardware
> > > > 32-bit limit instead of silently truncating the value.
> > >
> > > This is the intended behaviour.
> > >
> > > > Signed-off-by: Keguang Zhang <keguang.zhang@gmail.com>
> > > > ---
> > > >  drivers/pwm/pwm-loongson.c | 29 ++++++++++++++---------------
> > > >  1 file changed, 14 insertions(+), 15 deletions(-)
> > > >
> > > > diff --git a/drivers/pwm/pwm-loongson.c b/drivers/pwm/pwm-loongson.c
> > > > index 31a57edecfd0..dc77f82fd888 100644
> > > > --- a/drivers/pwm/pwm-loongson.c
> > > > +++ b/drivers/pwm/pwm-loongson.c
> > > > @@ -22,6 +22,7 @@
> > > >   */
> > > >
> > > >  #include <linux/acpi.h>
> > > > +#include <linux/bitfield.h>
> > > >  #include <linux/clk.h>
> > > >  #include <linux/device.h>
> > > >  #include <linux/init.h>
> > > > @@ -33,10 +34,12 @@
> > > >  #include <linux/units.h>
> > > >
> > > >  /* Loongson PWM registers */
> > > > -#define LOONGSON_PWM_REG_DUTY                0x4 /* Low Pulse Buffer Register */
> > > > +#define LOONGSON_PWM_REG_LOW         0x4 /* Low Pulse Buffer Register */
> > > >  #define LOONGSON_PWM_REG_PERIOD              0x8 /* Pulse Period Buffer Register */
> > > >  #define LOONGSON_PWM_REG_CTRL                0xc /* Control Register */
> > > >
> > > > +#define LOONGSON_PWM_MAX_PERIOD              GENMASK(31, 0)
> > > > +
> > > >  /* Control register bits */
> > > >  #define LOONGSON_PWM_CTRL_REG_EN     BIT(0)  /* Counter Enable Bit */
> > > >  #define LOONGSON_PWM_CTRL_REG_OE     BIT(3)  /* Pulse Output Enable Control Bit, Valid Low */
> > > > @@ -118,20 +121,16 @@ static int pwm_loongson_enable(struct pwm_chip *chip, struct pwm_device *pwm)
> > > >  static int pwm_loongson_config(struct pwm_chip *chip, struct pwm_device *pwm,
> > > >                              u64 duty_ns, u64 period_ns)
> > > >  {
> > > > -     u64 duty, period;
> > > > +     u64 low, period;
> > > >       struct pwm_loongson_ddata *ddata = to_pwm_loongson_ddata(chip);
> > > >
> > > > -     /* duty = duty_ns * ddata->clk_rate / NSEC_PER_SEC */
> > > > -     duty = mul_u64_u64_div_u64(duty_ns, ddata->clk_rate, NSEC_PER_SEC);
> > > > -     if (duty > U32_MAX)
> > > > -             duty = U32_MAX;
> > > > -
> > > > -     /* period = period_ns * ddata->clk_rate / NSEC_PER_SEC */
> > > >       period = mul_u64_u64_div_u64(period_ns, ddata->clk_rate, NSEC_PER_SEC);
> > > > -     if (period > U32_MAX)
> > > > -             period = U32_MAX;
> > > > +     if ((!FIELD_FIT(LOONGSON_PWM_MAX_PERIOD, period)))
> > > > +             return -ERANGE;
> > >
> > > As noted above, this is wrong. If period is too big, you're supposed to
> > > pick the biggest possible period and not return an error.
> > >
> >
> > Understood. However, in this case the difference between the requested
> > and actual
> > period can become quite significant. Returning success means userspace
> > may assume the requested configuration was applied while the generated
> > waveform is substantially different.
> >
> > Wouldn't returning an error be preferable in such cases, as it makes the
> > hardware limitation visible to userspace instead of silently applying a
> > different configuration?
>
> That sounds good, but doesn't work consistently and without surprises.
>
> Assuming a clk_rate of 24 MHz the maximal period is
>
>         0xffffffff / (24000000 Hz) = 178956970625 ns
>
> .
>
> Then with your suggestion implemented (as I understand it) the mapping
> from requested period to actual period looks as follows::
>
>         178956970624 ns -> 178956970583.33334 ns
>         178956970625 ns -> 178956970625 ns
>         ...
>         178956970666 ns -> 178956970625 ns
>         178956970667 ns -> -ERANGE
>
> From the consumer's point of view, how do you motivate that 178956970666
> still works while 178956970667 doesn't? IMHO the only consequent
> implementation then is to let 178956970626 already return an error.
> But then it's surprising again, that when requesting 178956970624 ns
> you get 178956970583.33334 ns on loongson, while for a hardware that has
> 178956970583.33334 ns as its maximal period, it's an error.
>
> That consideration convinced me back then to not return an error for too
> high values, which is the only sane option left then (unless I missed
> something?)
>
> With the waveform API you can query the capabilities and thus prevent
> consumer surprises.
>
Thanks for the detailed explanation.

I will drop the `-ERANGE` change and restore the original behavior
in the next version.

> Best regards
> Uwe



-- 
Best regards,

Keguang Zhang

^ permalink raw reply

* Re: [PATCH v2] ASoC: soc-core: Create device_link to ensure correct suspend order
From: Richard Fitzgerald @ 2026-06-23 10:22 UTC (permalink / raw)
  To: Marek Szyprowski, broonie
  Cc: linux-sound, linux-kernel, patches, Maxime Ripard, Dave Stevenson,
	linux-rpi-kernel, Florian Fainelli
In-Reply-To: <9298fa2f-a635-4055-a5ba-8b4971ecd5b1@samsung.com>

On 22/6/26 08:07, Marek Szyprowski wrote:
> On 20.06.2026 17:57, Richard Fitzgerald wrote:
>> On 17/6/26 15:10, Marek Szyprowski wrote:
>>> On 11.06.2026 13:08, Richard Fitzgerald wrote:
>>>> In snd_soc_bind_card() create a device_link from card to all components
>>>> to ensure correct order of system_suspend. The card is the consumer and
>>>> the components are the supplier, so that the card will system_suspend
>>>> before any of the components.
>>>>
>>
>> <SNIP>
>>
>>> This patch landed recently in linux-next as commit 0f54ce994b23 ("ASoC:
>>> soc-core: Create device_link to ensure correct suspend order"). In my
>>> tests I found that it breaks probing of VC4 DRM subsystem on Raspberry Pi
>>> 3 and 4 boards due to an issue with hdmi-audio-codec:
>>>
>>> # dmesg | grep vc4
>>> vc4-drm gpu: bound fe400000.hvs (ops vc4_hvs_ops [vc4])
>>> vc4_hdmi fef00700.hdmi: Failed to create device link to hdmi-audio-codec.1.auto
>>> vc4_hdmi fef00700.hdmi: error -EINVAL: Could not register sound card
>>> vc4-drm gpu: failed to bind fef00700.hdmi (ops vc4_hdmi_ops [vc4]): -22
>>> vc4-drm gpu: adev bind failed: -22
>>> vc4-drm gpu: probe with driver vc4-drm failed with error -22
>>>
>> Marek,
>>
>> Can you try the patch below?
>>
>> If this works for you, and passes our tests, and nobody has any
>> objections, I can send it as a proper patch submission.
> 
> 
> The patch was completely malformed (broken lines, tabs vs. spaces), I had to apply
> it manually line by line, but it fixed the issue I've observed:

Sorry. I forgot that copy-pasting it into an email would do line
wrapping


^ permalink raw reply

* Re: [PATCH v2 2/3] staging: media: atomisp: use kvmalloc_objs() for overflow-safe allocation
From: Andy Shevchenko @ 2026-06-23 10:22 UTC (permalink / raw)
  To: Rodrigo Gobbi
  Cc: andy, hansg, mchehab, sakari.ailus, gregkh, ~lkcamp/patches,
	linux-kernel-mentees, linux-kernel, linux-media, linux-staging
In-Reply-To: <20260622224402.34001-3-rodrigo.gobbi.7@gmail.com>

On Mon, Jun 22, 2026 at 07:42:43PM -0300, Rodrigo Gobbi wrote:
> Several allocations in sh_css_params.c still size their buffers with
> open-coded multiplication (e.g. width * height * sizeof(*p)), which can
> silently overflow and under-allocate.
> 
> Convert them to kvmalloc_objs() with array_size(), which saturate to
> SIZE_MAX on overflow so kvmalloc() returns NULL instead of allocating
> too few bytes.

...

> +	me->hor_coefs = kvmalloc_objs(*me->hor_coefs,
> +				      array_size(grid->num_hor_coefs,
> +						 IA_CSS_DVS_NUM_COEF_TYPES));

Here and elsewhere with long line, do like you have done in one case
with a temporary variable cnt. It makes same number of lines of code,
but readability is better.

>  	if (!me->hor_coefs)
>  		goto err;

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply

* [PATCH] mmc: dw_mmc: add declaration of dw_mci_pmops
From: Ben Dooks @ 2026-06-23 10:23 UTC (permalink / raw)
  To: Jaehoon Chung, Shawn Lin, Ulf Hansson, linux-mmc, linux-kernel; +Cc: Ben Dooks

The dw_mci_pmops is exported out of dw_mmc.c so add a declaration of
it in dw_mmc.h to fix the following sparse warning:

drivers/mmc/host/dw_mmc.c:3512:25: warning: symbol 'dw_mci_pmops' was not declared. Should it be static?

Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
 drivers/mmc/host/dw_mmc.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 9ffcd3946cff..38610c89d54a 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -19,6 +19,8 @@
 #include <linux/interrupt.h>
 #include <linux/workqueue.h>
 
+extern const struct dev_pm_ops dw_mci_pmops;
+
 enum dw_mci_state {
 	STATE_IDLE = 0,
 	STATE_SENDING_CMD,
-- 
2.37.2.352.g3c44437643


^ permalink raw reply related

* Re: [PATCH v2 1/3] rust: sync: Add abstraction for synchronize_rcu()
From: Miguel Ojeda @ 2026-06-23 10:24 UTC (permalink / raw)
  To: phasta, Gary Guo
  Cc: Pedro Falcato, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Alexandre Courbot, Onur Özkan, Alexander Viro,
	Christian Brauner, Jan Kara, Lyude Paul, Paul E. McKenney,
	Frederic Weisbecker, Neeraj Upadhyay, Joel Fernandes,
	Josh Triplett, Uladzislau Rezki, Steven Rostedt,
	Mathieu Desnoyers, Lai Jiangshan, Zqiang, Christian Schrefl,
	rust-for-linux, linux-kernel, linux-fsdevel, rcu
In-Reply-To: <908762cb7fd90df1df70eda28363a0015c404527.camel@mailbox.org>

On Tue, Jun 23, 2026 at 11:49 AM Philipp Stanner <phasta@mailbox.org> wrote:
>
> But it would be interesting to know more about how in general Rust's
> unsafe comments are related to problems beyond UAF issues, and to what
> degree we want to document context requirements.

I am confused by the UAF there. Did you mean UB?

Rust's `unsafe` is about way more than just use-after-free -- it is
about all potential undefined behavior.

At the same time, it is not about merely "dangerous" things.

If you cannot possibly cause UB, then it is not in scope. Otherwise,
it is very much in scope and the safety preconditions/requirements
need to be clearly documented (`# Safety`) or justified (`//
SAFETY:`).

Now, sometimes it may not make a lot of sense to duplicate a ton of
information, so sometimes we lift text to the Rust module docs and
refer to it; and sometimes it may also make more sense to refer to
external docs. One way or another, the goal is to document the
requirements and what is going on as clearly as possible.

Cheers,
Miguel

^ permalink raw reply

* [PATCH v2] rust: helpers: move list_lru and task_work helpers out of binder.c
From: Xiaobo Liu @ 2026-06-23 10:24 UTC (permalink / raw)
  To: rust-for-linux
  Cc: ojeda, miguel.ojeda.sandonis, akpm, david, qi.zheng,
	roman.gushchin, muchun.song, boqun, gary, bjorn3_gh, lossin,
	a.hindborg, aliceryhl, tmgross, linux-kernel, linux-mm,
	Xiaobo Liu
In-Reply-To: <CANiq72=sSkApehxg6eEpAoNU8zSsRAfqD+RVymM3UQGuvfKyeQ@mail.gmail.com>

The helpers in binder.c wrap generic list_lru and task_work inline
functions and have nothing to do with binder. Move each of them to a
file named after its own C header:

  - list_lru helpers move to list_lru.c,
  - init_task_work moves to task_work.c.

Add the new list_lru.c to the SHRINKER entry in MAINTAINERS, which
already covers include/linux/list_lru.h.

Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com>
---
 MAINTAINERS                           |  1 +
 rust/helpers/helpers.c                |  3 ++-
 rust/helpers/{binder.c => list_lru.c} |  7 -------
 rust/helpers/task_work.c              | 13 +++++++++++++
 4 files changed, 16 insertions(+), 8 deletions(-)
 rename rust/helpers/{binder.c => list_lru.c} (72%)
 create mode 100644 rust/helpers/task_work.c

diff --git a/MAINTAINERS b/MAINTAINERS
index ba45953bb..428992431 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -24590,6 +24590,7 @@ S:	Maintained
 F:	Documentation/admin-guide/mm/shrinker_debugfs.rst
 F:	include/linux/list_lru.h
 F:	include/linux/shrinker.h
+F:	rust/helpers/list_lru.c
 F:	mm/list_lru.c
 F:	mm/shrinker.c
 F:	mm/shrinker_debug.c
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index 998e31052..ea34101b9 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -43,7 +43,6 @@
 #include "atomic_ext.c"
 #include "auxiliary.c"
 #include "barrier.c"
-#include "binder.c"
 #include "bitmap.c"
 #include "bitops.c"
 #include "blk.c"
@@ -69,6 +68,7 @@
 #include "jump_label.c"
 #include "kunit.c"
 #include "list.c"
+#include "list_lru.c"
 #include "maple_tree.c"
 #include "mm.c"
 #include "mutex.c"
@@ -93,6 +93,7 @@
 #include "string.c"
 #include "sync.c"
 #include "task.c"
+#include "task_work.c"
 #include "time.c"
 #include "uaccess.c"
 #include "usb.c"
diff --git a/rust/helpers/binder.c b/rust/helpers/list_lru.c
similarity index 72%
rename from rust/helpers/binder.c
rename to rust/helpers/list_lru.c
index a2327f1b3..3b88d1a96 100644
--- a/rust/helpers/binder.c
+++ b/rust/helpers/list_lru.c
@@ -5,7 +5,6 @@
  */
 
 #include <linux/list_lru.h>
-#include <linux/task_work.h>
 
 __rust_helper unsigned long rust_helper_list_lru_count(struct list_lru *lru)
 {
@@ -19,9 +18,3 @@ __rust_helper unsigned long rust_helper_list_lru_walk(struct list_lru *lru,
 {
 	return list_lru_walk(lru, isolate, cb_arg, nr_to_walk);
 }
-
-__rust_helper void rust_helper_init_task_work(struct callback_head *twork,
-					      task_work_func_t func)
-{
-	init_task_work(twork, func);
-}
diff --git a/rust/helpers/task_work.c b/rust/helpers/task_work.c
new file mode 100644
index 000000000..cb961cd22
--- /dev/null
+++ b/rust/helpers/task_work.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (C) 2025 Google LLC.
+ */
+
+#include <linux/task_work.h>
+
+__rust_helper void rust_helper_init_task_work(struct callback_head *twork,
+					      task_work_func_t func)
+{
+	init_task_work(twork, func);
+}
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH] mm: avoid KCSAN false positive in page_to_nid()
From: Lorenzo Stoakes @ 2026-06-23 10:25 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Hui Zhu, Andrew Morton, Liam R. Howlett, Vlastimil Babka,
	Mike Rapoport, Suren Baghdasaryan, Michal Hocko, linux-mm,
	linux-kernel, Hui Zhu
In-Reply-To: <97f2c4ad-c302-424d-a7c8-fdfa0fc0d811@kernel.org>

On Tue, Jun 23, 2026 at 09:59:45AM +0200, David Hildenbrand (Arm) wrote:
> On 6/23/26 09:41, Hui Zhu wrote:
> > From: Hui Zhu <zhuhui@kylinos.cn>
> >
> > KCSAN reports a data race between page_to_nid() reading page->flags
> > and folio_trylock()/folio_lock() doing test_and_set_bit_lock(PG_locked,
> > ...) on the same word from another CPU, e.g.:
> >
> >   BUG: KCSAN: data-race in __lruvec_stat_mod_folio / shmem_get_folio_gfp
> >
> > The node id occupies a fixed, high bit-range of page->flags that is
> > set once when the page is initialized and never modified afterwards,
> > so it can never overlap with the low PG_locked/PG_waiters bits touched
> > by the folio lock path. The race is therefore harmless: page_to_nid()
> > always returns a consistent value regardless of how the read
> > interleaves with the lock bit ops.
> >
> > Wrap the flags read with data_race() to tell KCSAN this race is
> > intentional and benign, consistent with how page->page_type is
> > already annotated for similar packed-field accesses.
> >
> > Signed-off-by: Hui Zhu <zhuhui@kylinos.cn>

How did you discover this?

A syzbot report? If so please include Reported-by, Closes tags.

> > ---
> >  include/linux/mm.h | 9 ++++++++-
> >  1 file changed, 8 insertions(+), 1 deletion(-)
> >
> > diff --git a/include/linux/mm.h b/include/linux/mm.h
> > index 485df9c2dbdd..122d3b39369f 100644
> > --- a/include/linux/mm.h
> > +++ b/include/linux/mm.h
> > @@ -2296,7 +2296,14 @@ static inline int memdesc_nid(memdesc_flags_t mdf)
> >
> >  static inline int page_to_nid(const struct page *page)
> >  {
> > -	return memdesc_nid(PF_POISONED_CHECK(page)->flags);
> > +	/*
> > +	 * The node id occupies a fixed high bit-range of page->flags
> > +	 * that is set once at page init and never changed afterwards.
> > +	 * It cannot overlap with the low PG_locked/PG_waiters bits
> > +	 * that folio_lock()/folio_unlock() concurrently update, so
> > +	 * this data race is benign.
> > +	 */
>
> Do we really need this excessive comment?

Agreed, just delete it. For a trivial benign data race it's a bit much, and the
commit message can cover it off for those who are curious.

>
> > +	return memdesc_nid(data_race(PF_POISONED_CHECK(page)->flags));
>
> In memdesc_zonenum() we use ASSERT_EXCLUSIVE_BITS.
>
> Can we do the same here inside memdesc_nid?

Also agreed

>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 69daeeab7fe8f..76d3bb54be844 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -2290,6 +2290,7 @@ int memdesc_nid(memdesc_flags_t mdf);
>  #else
>  static inline int memdesc_nid(memdesc_flags_t mdf)
>  {
> +       ASSERT_EXCLUSIVE_BITS(mdf.f, NODES_MASK << NODES_PGSHIFT);
>         return (mdf.f >> NODES_PGSHIFT) & NODES_MASK;
>  }
>  #endif
>
>
> --
> Cheers,
>
> David

Thanks, Lorenzo

^ permalink raw reply

* Re: [PATCH] netfs: Fix UAF in netfs_unbuffered_write() on failed preparation
From: Christian Brauner @ 2026-06-23 10:28 UTC (permalink / raw)
  To: hongao
  Cc: David Howells, Paulo Alcantara, netfs, linux-fsdevel,
	linux-kernel, syzbot+3c74b1f0c372e98efc32
In-Reply-To: <FA1EF9EEE4C1415E+20260530011403.1686344-1-hongao@uniontech.com>

On 2026-05-30 09:14 +0800, hongao wrote:
> If write subrequest preparation fails, netfs_unbuffered_write() calls
> netfs_write_subrequest_terminated() and then reads subreq->error to set
> wreq->error.
> 
> However, netfs_write_subrequest_terminated() consumes a reference to the
> subrequest through netfs_put_subrequest(), so the subrequest may be freed
> before netfs_unbuffered_write() reads subreq->error again.  This can
> trigger a slab-use-after-free.
> 
> Save the error locally before terminating the subrequest, and use the
> saved value afterwards.
> 
> Fixes: a0b4c7a49137 ("netfs: Fix unbuffered/DIO writes to dispatch subrequests in strict sequence")
> Reported-by: syzbot+3c74b1f0c372e98efc32@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=3c74b1f0c372e98efc32
> 
> Signed-off-by: hongao <hongao@uniontech.com>
> ---

David?


^ permalink raw reply

* Re: [PATCH v4 1/3] bus: mhi: host: clients: Add loopback driver with sysfs interface
From: Sumit Kumar @ 2026-06-23 10:28 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: mhi, linux-arm-msm, linux-kernel, Krishna Chaitanya Chundru
In-Reply-To: <gwcckverwvbt7r4puj2iu2b2j36olwwu4ua4x4uthht7bfq6my@yifjh6swxisq>



On 6/23/2026 2:15 PM, Manivannan Sadhasivam wrote:
> On Mon, Jun 22, 2026 at 10:39:15AM +0530, Sumit Kumar wrote:
>> The MHI specification defines a LOOPBACK channel. The endpoint firmware
>> echoes back whatever the host sends on this channel. Without a host-side
>> driver, there is no way to exercise this channel to validate MHI data path
>> integrity between host and endpoint.
>>
>> Add a host-side loopback driver that binds to the LOOPBACK channel and
>> expose a sysfs interface for data path testing. The sysfs interface allows
>> users to configure TRE buffer size and count, trigger a loopback test, and
>> read the result.
>>
>> Co-developed-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
>> Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
>> Signed-off-by: Sumit Kumar <sumit.kumar@oss.qualcomm.com>
>> ---
>>   .../ABI/testing/sysfs-bus-mhi-devices-loopback     |  51 ++++
>>   MAINTAINERS                                        |   1 +
>>   drivers/bus/mhi/host/Kconfig                       |   1 +
>>   drivers/bus/mhi/host/Makefile                      |   1 +
>>   drivers/bus/mhi/host/clients/Kconfig               |  17 ++
>>   drivers/bus/mhi/host/clients/Makefile              |   2 +
>>   drivers/bus/mhi/host/clients/loopback.c            | 329 +++++++++++++++++++++
>>   7 files changed, 402 insertions(+)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-bus-mhi-devices-loopback b/Documentation/ABI/testing/sysfs-bus-mhi-devices-loopback
>> new file mode 100644
>> index 0000000000000000000000000000000000000000..3bd770747799a3341a23903cc1a108e650e915b8
>> --- /dev/null
>> +++ b/Documentation/ABI/testing/sysfs-bus-mhi-devices-loopback
>> @@ -0,0 +1,51 @@
>> +What:		/sys/bus/mhi/devices/mhi<N>_LOOPBACK/tre_size
>> +Date:		April 2026
>> +KernelVersion:	7.1
>> +Contact:	mhi@lists.linux.dev
>> +Description:
>> +		(RW) Size of each Transfer Ring Element (TRE) buffer in bytes
>> +		used for the loopback test. Valid range is 1 to the value
>> +		reported by max_tre_size. Default value is 32 bytes.
>> +
>> +What:		/sys/bus/mhi/devices/mhi<N>_LOOPBACK/max_tre_size
>> +Date:		April 2026
>> +KernelVersion:	7.1
>> +Contact:	mhi@lists.linux.dev
>> +Description:
>> +		(RO) Maximum allowed TRE size in bytes. Reading this file
>> +		returns the upper bound for the tre_size attribute.
>> +
>> +What:		/sys/bus/mhi/devices/mhi<N>_LOOPBACK/num_tre
>> +Date:		April 2026
>> +KernelVersion:	7.1
>> +Contact:	mhi@lists.linux.dev
>> +Description:
>> +		(RW) Number of Transfer Ring Elements (TREs) to use per
>> +		loopback test. Must be greater than zero and must not exceed
>> +		the channel ring capacity. Default value is 1.
>> +
>> +What:		/sys/bus/mhi/devices/mhi<N>_LOOPBACK/start
>> +Date:		April 2026
>> +KernelVersion:	7.1
>> +Contact:	mhi@lists.linux.dev
>> +Description:
>> +		(WO) Write any value to trigger a loopback test. The driver
>> +		sends random data to the endpoint using the configured tre_size
>> +		and num_tre parameters, waits for the endpoint to echo it back,
>> +		and verifies the received data matches what was sent.
>> +
>> +		This is a blocking write that returns when the test completes
>> +		or times out after 5 seconds.
>> +
>> +What:		/sys/bus/mhi/devices/mhi<N>_LOOPBACK/status
>> +Date:		April 2026
>> +KernelVersion:	7.1
>> +Contact:	mhi@lists.linux.dev
>> +Description:
>> +		(RO) Result of the last loopback test. Returns one of:
>> +		  "pass"        - last test completed successfully
>> +		  "fail"        - last test failed
>> +		  "not started" - no test has been run yet
>> +
>> +		Reading this file while a test is in progress will block
>> +		until the test completes.
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 6dcfbd11efef87927041f5cf58d70633dbb4b18d..ff12a6da48947ac853bc638359a7046fea85fc21 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -16441,6 +16441,7 @@ L:	linux-arm-msm@vger.kernel.org
>>   S:	Maintained
>>   T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mani/mhi.git
>>   F:	Documentation/ABI/stable/sysfs-bus-mhi
>> +F:	Documentation/ABI/testing/sysfs-bus-mhi-devices-loopback
>>   F:	Documentation/mhi/
>>   F:	drivers/bus/mhi/
>>   F:	drivers/pci/endpoint/functions/pci-epf-mhi.c
>> diff --git a/drivers/bus/mhi/host/Kconfig b/drivers/bus/mhi/host/Kconfig
>> index da5cd0c9fc620ab595e742c422f1a22a2a84c7b9..627c57948235aa52348179ae8b2d0826ebaed01e 100644
>> --- a/drivers/bus/mhi/host/Kconfig
>> +++ b/drivers/bus/mhi/host/Kconfig
>> @@ -29,3 +29,4 @@ config MHI_BUS_PCI_GENERIC
>>   	  This driver provides MHI PCI controller driver for devices such as
>>   	  Qualcomm SDX55 based PCIe modems.
>>   
>> +source "drivers/bus/mhi/host/clients/Kconfig"
>> diff --git a/drivers/bus/mhi/host/Makefile b/drivers/bus/mhi/host/Makefile
>> index 859c2f38451c669b3d3014c374b2b957c99a1cfe..2a16008aeb38127494782bbff4e1656428d2b776 100644
>> --- a/drivers/bus/mhi/host/Makefile
>> +++ b/drivers/bus/mhi/host/Makefile
>> @@ -4,3 +4,4 @@ mhi-$(CONFIG_MHI_BUS_DEBUG) += debugfs.o
>>   
>>   obj-$(CONFIG_MHI_BUS_PCI_GENERIC) += mhi_pci_generic.o
>>   mhi_pci_generic-y += pci_generic.o
>> +obj-y += clients/
>> diff --git a/drivers/bus/mhi/host/clients/Kconfig b/drivers/bus/mhi/host/clients/Kconfig
>> new file mode 100644
>> index 0000000000000000000000000000000000000000..d1463c3e0df0da461c815afaec623ba349b51dda
>> --- /dev/null
>> +++ b/drivers/bus/mhi/host/clients/Kconfig
>> @@ -0,0 +1,17 @@
>> +# SPDX-License-Identifier: GPL-2.0
>> +
>> +config MHI_BUS_LOOPBACK
>> +	tristate "MHI LOOPBACK client driver"
>> +	depends on MHI_BUS
>> +	help
>> +	  MHI LOOPBACK client driver that binds to the MHI LOOPBACK channel
>> +	  as defined in the MHI specification. The LOOPBACK channel is
>> +	  implemented by MHI-based devices (modems, WLAN) in the field, where
>> +	  the endpoint firmware echoes back whatever the host sends.
>> +
>> +	  This driver exposes a sysfs interface for testing MHI data path
>> +	  integrity between host and endpoint. Users can configure the TRE
>> +	  size and count, trigger a loopback test, and read the result.
>> +
>> +	  To compile this driver as a module, choose M here. The module
>> +	  will be called mhi_loopback.
>> diff --git a/drivers/bus/mhi/host/clients/Makefile b/drivers/bus/mhi/host/clients/Makefile
>> new file mode 100644
>> index 0000000000000000000000000000000000000000..3811b6928f42b38f94b1167941cf3b0fe512d32b
>> --- /dev/null
>> +++ b/drivers/bus/mhi/host/clients/Makefile
>> @@ -0,0 +1,2 @@
>> +obj-$(CONFIG_MHI_BUS_LOOPBACK) += mhi_loopback.o
>> +mhi_loopback-y += loopback.o
>> diff --git a/drivers/bus/mhi/host/clients/loopback.c b/drivers/bus/mhi/host/clients/loopback.c
>> new file mode 100644
>> index 0000000000000000000000000000000000000000..693691fff26dc8fa0d58931b98ce5f287fbd5c3e
>> --- /dev/null
>> +++ b/drivers/bus/mhi/host/clients/loopback.c
>> @@ -0,0 +1,329 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>> + */
>> +
>> +/*
>> + * The MHI LOOPBACK channel is defined in the MHI specification and is
>> + * implemented by MHI-based devices (modems, WLAN) already deployed in the
>> + * field. The endpoint firmware echoes back whatever the host sends on this
>> + * channel. This driver binds to the LOOPBACK channel and exposes a sysfs
>> + * interface for testing MHI data path integrity between host and endpoint.
>> + * The sysfs interface is stable ABI because the wire protocol is fixed by
>> + * the endpoint firmware and cannot be changed.
>> + */
> This comment just duplicates Kconfig help text. So drop it.
>
>> +
>> +#include <linux/atomic.h>
>> +#include <linux/cleanup.h>
>> +#include <linux/completion.h>
>> +#include <linux/errno.h>
>> +#include <linux/mhi.h>
>> +#include <linux/mod_devicetable.h>
>> +#include <linux/module.h>
>> +#include <linux/mutex.h>
>> +#include <linux/random.h>
>> +#include <linux/sizes.h>
>> +#include <linux/slab.h>
>> +#include <linux/string.h>
>> +#include <linux/sysfs.h>
>> +#include <linux/types.h>
>> +
>> +#define MHI_LOOPBACK_DEFAULT_TRE_SIZE	32
>> +#define MHI_LOOPBACK_DEFAULT_NUM_TRE	1
>> +#define MHI_LOOPBACK_TIMEOUT_MS		5000
>> +#define MHI_LOOPBACK_MAX_TRE_SIZE	(SZ_64K - 1)
>> +
>> +struct mhi_loopback {
>> +	struct mhi_device *mdev;
>> +	struct mutex lb_mutex;
>> +	struct completion comp;
>> +	atomic_t tres_pending;
> tre_pending
>
>> +	const char *result;
>> +	u32 num_tre;
>> +	u32 tre_size;
>> +};
>> +
>> +static ssize_t tre_size_show(struct device *dev,
>> +			     struct device_attribute *attr, char *buf)
>> +{
>> +	struct mhi_loopback *loopback = dev_get_drvdata(dev);
>> +
>> +	if (!loopback)
>> +		return -ENODEV;
> I think you have this check here to avoid race between sysfs cleanup and driver
> remove due to the use of devm_device_add_group(). But you can drop these by
> switching to non-devm helpers and freeing the sysfs entries directly in
> mhi_loopback_remove().
>
>> +
>> +	return sysfs_emit(buf, "%u\n", loopback->tre_size);
>> +}
>> +
>> +static ssize_t tre_size_store(struct device *dev,
>> +			      struct device_attribute *attr,
>> +			      const char *buf, size_t count)
>> +{
>> +	struct mhi_loopback *loopback = dev_get_drvdata(dev);
>> +	u32 val;
>> +
>> +	if (!loopback)
>> +		return -ENODEV;
>> +
>> +	if (kstrtou32(buf, 0, &val))
>> +		return -EINVAL;
>> +
>> +	if (val == 0 || val > MHI_LOOPBACK_MAX_TRE_SIZE)
>> +		return -EINVAL;
>> +
>> +	guard(mutex)(&loopback->lb_mutex);
>> +	loopback->tre_size = val;
>> +
>> +	return count;
>> +}
>> +static DEVICE_ATTR_RW(tre_size);
>> +
>> +static ssize_t max_tre_size_show(struct device *dev,
>> +				 struct device_attribute *attr, char *buf)
>> +{
>> +	return sysfs_emit(buf, "%u\n", MHI_LOOPBACK_MAX_TRE_SIZE);
>> +}
>> +static DEVICE_ATTR_RO(max_tre_size);
>> +
>> +static ssize_t num_tre_show(struct device *dev,
>> +			    struct device_attribute *attr, char *buf)
>> +{
>> +	struct mhi_loopback *loopback = dev_get_drvdata(dev);
>> +
>> +	if (!loopback)
>> +		return -ENODEV;
>> +
>> +	return sysfs_emit(buf, "%u\n", loopback->num_tre);
>> +}
>> +
>> +static ssize_t num_tre_store(struct device *dev,
>> +			     struct device_attribute *attr,
>> +			     const char *buf, size_t count)
>> +{
>> +	struct mhi_loopback *loopback = dev_get_drvdata(dev);
>> +	u32 val;
>> +	int el_num;
>> +
>> +	if (!loopback)
>> +		return -ENODEV;
>> +
>> +	if (kstrtou32(buf, 0, &val))
>> +		return -EINVAL;
>> +
>> +	if (val == 0)
>> +		return -EINVAL;
>> +
>> +	guard(mutex)(&loopback->lb_mutex);
>> +
>> +	el_num = mhi_get_free_desc_count(loopback->mdev, DMA_TO_DEVICE);
>> +	if (val > el_num) {
>> +		dev_err(dev, "num_tre (%u) exceeds ring capacity (%d)\n", val, el_num);
>> +		return -EINVAL;
>> +	}
>> +
>> +	loopback->num_tre = val;
>> +
>> +	return count;
>> +}
>> +static DEVICE_ATTR_RW(num_tre);
>> +
>> +static ssize_t start_store(struct device *dev,
>> +			   struct device_attribute *attr,
>> +			   const char *buf, size_t count)
>> +{
>> +	struct mhi_loopback *loopback = dev_get_drvdata(dev);
>> +	u32 total_size, tre_count, tre_size;
>> +	int i;
>> +
>> +	if (!loopback)
>> +		return -ENODEV;
>> +
>> +	guard(mutex)(&loopback->lb_mutex);
>> +
>> +	tre_size = loopback->tre_size;
>> +	tre_count = loopback->num_tre;
>> +	total_size = size_mul(tre_count, tre_size);
>> +
>> +	if (total_size > KMALLOC_MAX_SIZE)
>> +		return -EINVAL;
>> +
>> +	void *recv_buf __free(kfree) = kzalloc(total_size, GFP_KERNEL);
>> +	if (!recv_buf)
>> +		return -ENOMEM;
>> +
>> +	void *send_buf __free(kfree) = kzalloc(total_size, GFP_KERNEL);
>> +	if (!send_buf)
>> +		return -ENOMEM;
>> +
>> +	get_random_bytes(send_buf, total_size);
>> +
>> +	atomic_set(&loopback->tres_pending, tre_count);
>> +	reinit_completion(&loopback->comp);
>> +
>> +	for (i = 0; i < tre_count; i++) {
>> +		int ret = mhi_queue_buf(loopback->mdev, DMA_FROM_DEVICE,
>> +					recv_buf + (i * tre_size), tre_size, MHI_EOT);
>> +		if (ret) {
>> +			dev_err(dev, "Unable to queue read TRE %d: %d\n", i, ret);
>> +			loopback->result = "fail";
>> +			if (atomic_sub_and_test(tre_count - i, &loopback->tres_pending))
>> +				complete(&loopback->comp);
>> +			return ret;
>> +		}
>> +	}
>> +
>> +	for (i = 0; i < tre_count - 1; i++) {
>> +		int ret = mhi_queue_buf(loopback->mdev, DMA_TO_DEVICE,
>> +					send_buf + (i * tre_size), tre_size, MHI_CHAIN);
>> +		if (ret) {
>> +			dev_err(dev, "Unable to queue send TRE %d: %d\n", i, ret);
>> +			loopback->result = "fail";
>> +			return ret;
>> +		}
>> +	}
>> +
>> +	int ret = mhi_queue_buf(loopback->mdev, DMA_TO_DEVICE,
>> +				send_buf + (i * tre_size), tre_size, MHI_EOT);
>> +	if (ret) {
>> +		dev_err(dev, "Unable to queue final TRE: %d\n", ret);
>> +		loopback->result = "fail";
>> +		return ret;
>> +	}
>> +
>> +	if (!wait_for_completion_timeout(&loopback->comp,
>> +					 msecs_to_jiffies(MHI_LOOPBACK_TIMEOUT_MS))) {
>> +		dev_err(dev, "Loopback test timed out\n");
>> +		loopback->result = "fail";
>> +		return -ETIMEDOUT;
> So once this function exits, both buffers will get freed due to the destructor.
> But the device may still hold the reference to the buffers in TRE and may
> read/write to it later. So you need to make sure that you flush the buffers in
> the error path. But we don't have any explicit APIs to do that, so maybe you can
> call mhi_unprepare_from_transfer() followed by mhi_prepare_for_transfer() in the
> error path?
>
>> +	}
>> +
>> +	if (memcmp(send_buf, recv_buf, total_size)) {
>> +		dev_err(dev, "Loopback data mismatch\n");
>> +		loopback->result = "fail";
>> +		return -EIO;
>> +	}
>> +
>> +	loopback->result = "pass";
>> +
>> +	return count;
>> +}
>> +static DEVICE_ATTR_WO(start);
>> +
>> +static ssize_t status_show(struct device *dev,
>> +			   struct device_attribute *attr, char *buf)
>> +{
>> +	struct mhi_loopback *loopback = dev_get_drvdata(dev);
>> +
>> +	if (!loopback)
>> +		return -ENODEV;
>> +
>> +	guard(mutex)(&loopback->lb_mutex);
>> +
>> +	return sysfs_emit(buf, "%s\n", loopback->result);
> I don't see a need for this separate 'status' attribute. 'start' attribute
> blocks until the write is completed or timesout, prints an error message with
> relevant errno and returns the error code. Though the syscall interface converts
> all error code to (-1), it is sufficient for the userspace to know whether the
> test has passed or not.
>
>> +}
>> +static DEVICE_ATTR_RO(status);
>> +
>> +static void mhi_loopback_dl_callback(struct mhi_device *mhi_dev,
>> +				     struct mhi_result *mhi_res)
>> +{
>> +	struct mhi_loopback *loopback = dev_get_drvdata(&mhi_dev->dev);
>> +
>> +	if (!loopback)
>> +		return;
>> +
>> +	if (mhi_res->transaction_status && mhi_res->transaction_status != -ENOTCONN)
>> +		dev_err(&mhi_dev->dev, "DL callback error: status %d\n",
>> +			mhi_res->transaction_status);
>> +
>> +	if (atomic_dec_and_test(&loopback->tres_pending))
>> +		complete(&loopback->comp);
>> +}
>> +
>> +static void mhi_loopback_ul_callback(struct mhi_device *mhi_dev,
>> +				     struct mhi_result *mhi_res)
>> +{
>> +}
>> +
>> +static struct attribute *mhi_loopback_attrs[] = {
>> +	&dev_attr_tre_size.attr,
>> +	&dev_attr_max_tre_size.attr,
>> +	&dev_attr_num_tre.attr,
>> +	&dev_attr_start.attr,
>> +	&dev_attr_status.attr,
>> +	NULL,
>> +};
>> +
>> +static const struct attribute_group mhi_loopback_group = {
>> +	.attrs = mhi_loopback_attrs,
>> +};
>> +
>> +static int mhi_loopback_probe(struct mhi_device *mhi_dev,
>> +			      const struct mhi_device_id *id)
>> +{
>> +	struct mhi_loopback *loopback;
>> +	int rc;
> 'int ret'
>
>> +
>> +	loopback = devm_kzalloc(&mhi_dev->dev, sizeof(*loopback), GFP_KERNEL);
>> +	if (!loopback)
>> +		return -ENOMEM;
>> +
>> +	loopback->mdev = mhi_dev;
>> +	loopback->tre_size = MHI_LOOPBACK_DEFAULT_TRE_SIZE;
>> +	loopback->num_tre = MHI_LOOPBACK_DEFAULT_NUM_TRE;
>> +	loopback->result = "not started";
>> +
>> +	mutex_init(&loopback->lb_mutex);
>> +	init_completion(&loopback->comp);
>> +
>> +	dev_set_drvdata(&mhi_dev->dev, loopback);
>> +
>> +	rc = mhi_prepare_for_transfer(mhi_dev);
>> +	if (rc) {
>> +		dev_err(&mhi_dev->dev, "failed to prepare for transfers\n");
> nit: Capitalize 'Failed' and print the errno. Applies to all error prints.
>
>> +		return rc;
>> +	}
>> +
>> +	rc = devm_device_add_group(&mhi_dev->dev, &mhi_loopback_group);
>> +	if (rc) {
>> +		dev_err(&mhi_dev->dev, "failed to create sysfs attributes\n");
>> +		mhi_unprepare_from_transfer(mhi_dev);
>> +	}
>> +
>> +	return rc;
> 'return 0'
>
>> +}
>> +
>> +static void mhi_loopback_remove(struct mhi_device *mhi_dev)
>> +{
>> +	struct mhi_loopback *loopback = dev_get_drvdata(&mhi_dev->dev);
>> +
>> +	complete(&loopback->comp);
>> +
>> +	mutex_lock(&loopback->lb_mutex);
>> +	mutex_unlock(&loopback->lb_mutex);
> What does this locking protect?
since start_store() is holding the mutex for its entire duration,
this lock will block until any in-progress start_store() has fully
completed before teardown, ensuring  mhi_unprepare_from_transfer()
does not race with an active test still accessing the channel.

Will fix other things you have mentioned.

-  Sumit
>
>> +
>> +	mhi_unprepare_from_transfer(mhi_dev);
>> +	dev_set_drvdata(&mhi_dev->dev, NULL);
> As I mentioned above, once you call sysfs_create_group() in probe() and
> sysfs_remove_group() before mhi_unprepare_from_transfer(), you can drop setting
> drvdata to NULL.
>
> - Mani
>


^ permalink raw reply

* Re: [PATCH v6 0/3] ASoC: qcom: lpass: Switch VA/WSA macros to PM clock framework
From: Konrad Dybcio @ 2026-06-23 10:29 UTC (permalink / raw)
  To: Ajay Kumar Nandam, broonie, lgirdwood, perex, tiwai, srini
  Cc: linux-sound, linux-arm-msm, linux-kernel
In-Reply-To: <20260623071708.2822269-1-ajay.nandam@oss.qualcomm.com>

On 6/23/26 9:17 AM, Ajay Kumar Nandam wrote:
> Hi,
> 
> This series converts LPASS WSA and VA macro codec drivers to the PM clock
> framework for runtime PM clock handling, and keeps WSA MCLK-output clock
> registration resource-managed.
> 
> Changes since v5:
> - Rebased to current linux-next/master and regenerated as a standalone
>   series that applies cleanly.

Switch to using the b4 tool (https://b4.docs.kernel.org/). You sent
all messages as a separate thread.

Konrad

^ permalink raw reply

* Re: [PATCH v2 RFC 08/13] sched/qos: Add a new sched-qos interface
From: zhidao su @ 2026-06-23 10:28 UTC (permalink / raw)
  To: Qais Yousef
  Cc: zhidao su, Ingo Molnar, Peter Zijlstra, Vincent Guittot,
	Rafael J . Wysocki, Viresh Kumar, Juri Lelli, Steven Rostedt,
	John Stultz, Dietmar Eggemann, Tim Chen, Chen Yu C,
	Thomas Gleixner, linux-kernel, linux-pm
In-Reply-To: <20260504020003.71306-9-qyousef@layalina.io>

On Mon, May 04, 2026 at 02:59:58AM +0100, Qais Yousef wrote:
> Provide a generic and extensible interface to describe arbitrary QoS
> tags to tell the kernel about specific behavior that is doesn't fall
> into the existing sched_attr.
>
> The interface is broken into three parts:
>
> * Type
> * Value
> * Cookie

Hi Qais,

I tested the proposed ABI on an Android device running
6.18.20-android17-3-maybe-dirty-4k with this sched_qos series carried
locally. This was a direct syscall preflight rather than an app-level
benchmark:

  - set SCHED_FLAG_QOS / SCHED_QOS_RAMPUP_MULTIPLIER=4 on an existing
    task with sched_setattr();
  - read it back with sched_getattr() and check type/value;
  - repeat with value 0;
  - fail the test if sched_setattr() returns 0 but readback does not match.

This exposed two ABI semantics that I think need to be nailed down.

First, a QoS-only sched_setattr() can return success without applying the
QoS state.

In __sched_setscheduler(), the policy-unchanged fast path checks whether
nice, RT priority, DL params, or util-clamp changed before deciding there
is nothing to do. It does not treat SCHED_FLAG_QOS as a change there, so a
call that only changes sched_qos_type/value can return 0 before reaching
__setscheduler_sched_qos().

That makes syscall success ambiguous for a userspace manager: it needs to
read the state back to know whether the QoS request actually took effect.
I think SCHED_FLAG_QOS should be sufficient to force the change path.

Second, sched_getattr() uses sched_qos_type from the userspace sched_attr
buffer as the selector for which QoS value to report:

	if (copy_from_user(&kattr.sched_qos_type,
			   &uattr->sched_qos_type,
			   sizeof(kattr.sched_qos_type)))
		return -EFAULT;

	switch (kattr.sched_qos_type) {
	case SCHED_QOS_RAMPUP_MULTIPLIER:
		kattr.sched_qos_value = p->sched_qos.rampup_multiplier;
		kattr.sched_qos_cookie = 0;
		break;
	default:
		break;
	}

If this input-selector behavior is intentional, I think it should be
documented as part of the query ABI. Otherwise sched_getattr() looks like
an output-only operation, and helper code can easily confuse "I did not
select a QoS type to query" with "this task has no QoS state".

The same preflight also checked that short sched_attr sizes with
SCHED_FLAG_QOS fail predictably. That part does fail today, but indirectly
because the short copy leaves sched_qos_type as SCHED_QOS_NONE. It may be
clearer to make the required size for SCHED_FLAG_QOS explicit, similar to
the util-clamp size check.

With set/readback checks in place, I can observe a narrow scheduler-layer
signal in a controlled native transition workload. I would not treat that
as a generic Android UI latency result or a Tested-by tag, but the
preflight made the set/query semantics above stand out.

Thanks.

^ permalink raw reply

* Re: [PATCH] KVM: x86: Clamp the EOI vector if its OOB instead of bugging the kernel
From: Huang, Kai @ 2026-06-23 10:29 UTC (permalink / raw)
  To: seanjc@google.com
  Cc: kvm@vger.kernel.org, pbonzini@redhat.com,
	linux-kernel@vger.kernel.org
In-Reply-To: <ajnLWcMETdVnKVRc@google.com>

On Mon, 2026-06-22 at 16:55 -0700, Sean Christopherson wrote:
> On Fri, Jun 19, 2026, Kai Huang wrote:
> > On Thu, 2026-06-18 at 11:55 -0700, Sean Christopherson wrote:
> > > If KVM handles an I/O APIC EOI exit request with a bad vector, clamp the
> > > vector to 255 and hope for the best instead of bugging the host.  In all
> > > likelihood, a missed EOI is survivable for the guest, and it's most
> > > definitely not remotely fatal to the host, i.e. potentially panicking the
> > > host is completely unjustified.  Arbitrarily use 255 for the dummy vector,
> > > the goal is purely to ensure the vector is covered by the bitmap.
> > 
> > 255 is a valid vector.  How about use a CPU reserved one instead (e.g., vector
> > 0) and hope for the best?
> 
> I was thinking it would be better to err on the side of spuriously exiting to
> userspace, versus suppressing an exit?  And I wanted to keep the vector legal,
> in case something else in KVM cares about legal vectors?  Hmm, but using 255 is
> bad because it likely never be cleared, and thus will block other EOI exits due
> to 255 being the highest priority vector.
> 
> Ah, and the field is never explicitly initialized beyond the structutre being,
> so it's starting state is '0' as well.  My only hesitation with zero is that in
> the unlikely case bit 0 is set in ioapic_handled_vectors, userspace will be extra
> confused.  
> 

I was actually thinking 0 may be less confusing than 255.  A sane userspace
should just know 0 is a bad vector thus should report an error to admin, if not
kill the guest.  On the other hand, 255 is a valid vector so userspace may
wrongly EOI an incorrect IRQ, which could be more confusing to the guest or
userspace itself in the end?

Btw, I think killing the guest should be acceptable if such bug happens?  The
existing behaviour is to panic the host anyway ..

> But that's easy enough to deal with, just skip the check.

I am not sure ignoring the IOAPIC EOI exit (in case of this bug) is better than
reporting a invalid vector to userspace.  I guess it's fine, since the worst
case is userspace loses the EOI for an IRQ AFAICT, but I am not sure this is
better?

> 
> This?
> 
> 		if (kvm_check_request(KVM_REQ_IOAPIC_EOI_EXIT, vcpu)) {
> 			if (WARN_ON_ONCE(vcpu->arch.pending_ioapic_eoi < 0 ||
> 					 vcpu->arch.pending_ioapic_eoi > 255))
> 				vcpu->arch.pending_ioapic_eoi = 0;
> 			else if (test_bit(vcpu->arch.pending_ioapic_eoi,
> 					  vcpu->arch.ioapic_handled_vectors)) {
> 				vcpu->run->exit_reason = KVM_EXIT_IOAPIC_EOI;
> 				vcpu->run->eoi.vector =
> 						vcpu->arch.pending_ioapic_eoi;
> 				r = 0;
> 				goto out;
> 			}
> 		}

Either way works for me.  I am starting to think we care about this too much --
it's definitely better than BUG_ON() for sure :-)

^ permalink raw reply

* Re: [PATCH iwl-net] ice: clear the default forwarding VSI rule when releasing a VSI
From: Simon Horman @ 2026-06-23 10:29 UTC (permalink / raw)
  To: poros
  Cc: Simon Horman, netdev, anthony.l.nguyen, przemyslaw.kitszel,
	andrew+netdev, davem, edumazet, kuba, pabeni, jacob.e.keller,
	michal.swiatkowski, intel-wired-lan, linux-kernel
In-Reply-To: <20260622081030.2312129-1-poros@redhat.com>

This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://sashiko.dev
---
ice: clear the default forwarding VSI rule when releasing a VSI

This patch restores the cleanup of the default forwarding VSI rule
in ice_vsi_release(), clearing it when the VSI owns it. This prevents
a rule leak if a trusted VF enters promiscuous mode and is then destroyed.

> diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
> --- a/drivers/net/ethernet/intel/ice/ice_lib.c
> +++ b/drivers/net/ethernet/intel/ice/ice_lib.c
> @@ -2871,6 +2871,9 @@ int ice_vsi_release(struct ice_vsi *vsi)
>  		return -ENODEV;
>  	pf = vsi->back;
>  
> +	if (ice_is_vsi_dflt_vsi(vsi))
> +		ice_clear_dflt_vsi(vsi);
> +

[Severity: High]
Is there a time-of-check to time-of-use race here?

ice_is_vsi_dflt_vsi() acquires and releases the filt_rule_lock to check if
the current VSI is the default. If true, ice_clear_dflt_vsi() is called,
which acquires the lock again during rule removal.

If the lock is dropped between these two calls, could another thread
establish a new default VSI rule before ice_clear_dflt_vsi() runs?

When ice_clear_dflt_vsi() executes, it appears the rule search only matches
by l_data and flag:

ice_switch.c:ice_find_rule_entry() {
	if (!memcmp(&f_info->l_data, &list_itr->fltr_info.l_data,
		    sizeof(f_info->l_data)) &&
	    f_info->flag == list_itr->fltr_info.flag) {
        ...
}

For the default VSI rule, l_data is empty, so it might match any newly
established default rule.

And since ice_remove_rule_internal() does not appear to validate the
vsi_handle for non-list rules:

ice_switch.c:ice_remove_rule_internal() {
	if (list_elem->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST) {
		remove_rule = true;
        ...
}

Could this blindly remove the default forwarding configuration for a
completely unrelated VSI?

>  	if (test_bit(ICE_FLAG_RSS_ENA, pf->flags))
>  		ice_rss_clean(vsi);

^ permalink raw reply

* Re: [PATCH v2 0/8] HID: iio: Avoid race between callback setup and device exposure
From: Andy Shevchenko @ 2026-06-23 10:30 UTC (permalink / raw)
  To: Sanjay Chitroda
  Cc: Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada, David Lechner,
	Nuno Sá, Andy Shevchenko, Archana Patni, Song Hongyan,
	linux-input, linux-iio, linux-kernel, srinivas pandruvada
In-Reply-To: <20260622-5-june-hid-iio-race-fixes-v2-0-1cfabcd1881e@gmail.com>

On Mon, Jun 22, 2026 at 10:59:56AM +0530, Sanjay Chitroda wrote:
> 
> This series avoid a race condition in HID IIO drivers related to the
> ordering between callback registration and device exposure.
> 
> Currently, several HID IIO drivers register the IIO device (making it
> visible to userspace and other kernel consumers) before all required
> callbacks and resources are fully initialized, or rely on devm-based
> cleanup in a way that does not guarantee correct teardown ordering.
> This creates a window where the device can be accessed while it is

There is a difference between "this creates" and "this might create".
I believe Srinivas and others were asking for the proof. So, what path
in the code makes this happen or possible to happen?

> not fully initialized or is being torn down, potentially leading to
> sample drop or stale/no data.
> 
> To handle this, the series ensures that:
>   - All required callbacks and resources are set up before the device
>     is registered with the IIO core
>   - Resource cleanup is performed explicitly where ordering matters
> 
> PS: This is prepratory series to convert all HID IIO driver to devm.
> 
> Testing:
>   - Compiled with W=1 for each patch in series
> 
> ---
> Changes in v2:
> - Drop fixes tag and rectify commit message with reference to that

You also dropped my tag. Why?

> - Link to v1: https://patch.msgid.link/20260606-5-june-hid-iio-race-fixes-v1-0-27a848c5758f@gmail.com

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox