Skip to contentSkip to conversation

7.1.6-rc1 review

PATCH In review Greg Kroah-Hartman 18 participants 768 messages Jul 30 – Aug 2 Page 2 of 6

Subsystems (4)
lore
Share & tools
lore
author maintainer
#123 lore raw

PATCH 123/744 drm/xe/guc: Keep scheduler timeline name alive

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Arvind Yadav <[email protected]>

[ Upstream commit 299bc6d50b1bed7d1f408391736712f01a0855e2 ]

The scheduler keeps a pointer to the timeline name, but q->name is freed with the exec queue while scheduler fences can still reference it.

Store the name in struct xe_guc_exec_queue so it shares the scheduler's RCU-deferred lifetime.

Fixes 6bd90e700b42 ("drm/xe: Make dma-fences compliant with the safe access rules")
Cc Thomas Hellström <[email protected]>
Cc Rodrigo Vivi <[email protected]>
Cc Himal Prasad Ghimiray <[email protected]>
Cc Matthew Brost <[email protected]>
(cherry picked from commit 41075f0eb5dcbd3b065d15f15ef7bbe9315188e8)
---
 drivers/gpu/drm/xe/xe_guc_exec_queue_types.h | 5 +++++
 drivers/gpu/drm/xe/xe_guc_submit.c           | 4 +++-
 2 files changed, 8 insertions(+), 1 deletion(-)
drivers/gpu/drm/xe/xe_guc_exec_queue_types.h +5 -0
index e5e53b421f29fb..cda14d954e572f 100644
@@ -10,6 +10,7 @@
 #include <linux/workqueue.h>
 
 #include "xe_gpu_scheduler_types.h"
+#include "xe_hw_fence_types.h"
 
 struct dma_fence;
 struct xe_exec_queue;
@@ -24,6 +25,10 @@ struct xe_guc_exec_queue {
 	struct rcu_head rcu;
 	/** @sched: GPU scheduler for this xe_exec_queue */
 	struct xe_gpu_scheduler sched;
+	/**
+	 * @name: Scheduler timeline name, kept with @sched until RCU free.
+	 */
+	char name[MAX_FENCE_NAME_LEN];
 	/** @entity: Scheduler entity for this xe_exec_queue */
 	struct xe_sched_entity entity;
 	/**
drivers/gpu/drm/xe/xe_guc_submit.c +3 -1
index 1752039d333f39..54606367eea3b3 100644
@@ -1973,6 +1973,8 @@ static int guc_exec_queue_init(struct xe_exec_queue *q)
 
 	xe_exec_queue_assign_name(q, q->guc->id);
 
+	strscpy(ge->name, q->name, sizeof(ge->name));
+
 	/*
 	 * Use primary queue's submit_wq for all secondary queues of a
 	 * multi queue group. This serialization avoids any locking around
@@ -1987,7 +1989,7 @@ static int guc_exec_queue_init(struct xe_exec_queue *q)
 	err = xe_sched_init(&ge->sched, &drm_sched_ops, &xe_sched_ops,
 			    submit_wq, xe_lrc_ring_size() / MAX_JOB_SIZE_BYTES, 64,
 			    timeout, guc_to_gt(guc)->ordered_wq, NULL,
-			    q->name, gt_to_xe(q->gt)->drm.dev);
+			    ge->name, gt_to_xe(q->gt)->drm.dev);
 	if (err)
 		goto err_release_id;
 
Signature · 1 line
2.53.0
author maintainer
#124 lore raw

PATCH 124/744 drm/xe/guc: Hold device ref until queue teardown completes

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Arvind Yadav <[email protected]>

[ Upstream commit 9b7e60184f4b22e893d4ae95234d5f26261a430c ]

GuC exec queue destruction can run asynchronously. If the final device put happens from a destroy worker, drmm cleanup can end up draining the same workqueue and deadlock.

Hold a drm_device reference for the queue lifetime and drop it after queue teardown completes. This keeps drmm cleanup from running while async destroy work is still pending.

Move GuC destroy work to a module-lifetime Xe workqueue and flush it on PCI remove so hot-unbind/rebind still waits for pending destroy work.

With queue-held device refs, guc_submit_sw_fini() cannot run with live GuC IDs. Replace the fini wait with an assertion and remove the unused fini_wq.

v2:
- Rebase

v3:
- Switch to queue-lifetime drm_dev_get()/drm_dev_put() model. (Matt)
- Queue async teardown on system_dfl_wq instead of xe->destroy_wq. (Matt)
- Drop separate deferred drm_dev_put worker.
- Remove stale drain_workqueue(xe->destroy_wq) from guc_submit_sw_fini().

v4:
- Replace the guc_submit_sw_fini() wait with an assertion and remove the now-unused fini_wq. (sashiko)

v5:
- Move destroy work to a module-lifetime Xe workqueue instead of system_dfl_wq. (Matt)
- Flush the module-lifetime destroy workqueue during PCI remove to preserve the old device-remove wait semantics.

v6:
- Keep SVM pagemap destroy work on the per-device destroy_wq to avoid letting it outlive the xe_device/drm_device. (Sashiko)
- Use WQ_MEM_RECLAIM for xe->destroy_wq because SVM pagemap destroy work can be queued from the reclaim path.

v7:
- Drop the per-device xe->destroy_wq and use the module-level destroy WQ for SVM pagemap destroy as well. (Matt)
- Rename xe_exec_queue_destroy_wq_*() helpers to xe_destroy_wq_*() helpers because the WQ is no longer exec-queue specific. (Matt)

v8:
- Rebase.

v9:
- Keep SVM pagemap destroy work on the per-device WQ_MEM_RECLAIM destroy_wq because it can be queued from reclaim and embeds the dev_pagemap used by devres teardown. (Sashiko)
- Keep the module-level destroy WQ GuC-only and drop WQ_MEM_RECLAIM from it.
- Update the module-WQ kdoc to document the GuC/SVM split.

v10:
- Keep xe->destroy_wq per-cpu while adding WQ_MEM_RECLAIM to fix the workqueue allocation warning.

v11:
- Drop the SVM pagemap destroy comment as it was revision-specific. (Thomas)

v12:
- Rebase.

Fixes 2d2be279f1ca ("drm/xe: fix UAF around queue destruction")
Cc Thomas Hellström <[email protected]>
Cc Rodrigo Vivi <[email protected]>
Cc Himal Prasad Ghimiray <[email protected]>
Cc Tejas Upadhyay <[email protected]>
(cherry picked from commit da1124abac689cc2b1d8995e5f0a816f8a122edb)
---
 drivers/gpu/drm/xe/xe_device.c       |  2 +-
 drivers/gpu/drm/xe/xe_device_types.h |  2 +-
 drivers/gpu/drm/xe/xe_guc_submit.c   | 66 ++++++++++++++++------------
 drivers/gpu/drm/xe/xe_guc_types.h    |  2 -
 drivers/gpu/drm/xe/xe_module.c       | 49 +++++++++++++++++++++
 drivers/gpu/drm/xe/xe_module.h       |  5 +++
 drivers/gpu/drm/xe/xe_pci.c          |  6 +++
 7 files changed, 100 insertions(+), 32 deletions(-)
drivers/gpu/drm/xe/xe_device.c +1 -1
index ffea4a453c01ca..991b0ea9218bb2 100644
@@ -509,7 +509,7 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
 						       WQ_MEM_RECLAIM);
 	xe->ordered_wq = alloc_ordered_workqueue("xe-ordered-wq", 0);
 	xe->unordered_wq = alloc_workqueue("xe-unordered-wq", WQ_PERCPU, 0);
-	xe->destroy_wq = alloc_workqueue("xe-destroy-wq", WQ_PERCPU, 0);
+	xe->destroy_wq = alloc_workqueue("xe-destroy-wq", WQ_PERCPU | WQ_MEM_RECLAIM, 0);
 	if (!xe->ordered_wq || !xe->unordered_wq ||
 	    !xe->preempt_fence_wq || !xe->destroy_wq) {
 		/*
drivers/gpu/drm/xe/xe_device_types.h +1 -1
index 615218d775b14e..7e0901ac95c91d 100644
@@ -351,7 +351,7 @@ struct xe_device {
 	/** @unordered_wq: used to serialize unordered work */
 	struct workqueue_struct *unordered_wq;
 
-	/** @destroy_wq: used to serialize user destroy work, like queue */
+	/** @destroy_wq: used to serialize SVM pagemap destroy work */
 	struct workqueue_struct *destroy_wq;
 
 	/** @tiles: device tiles */
drivers/gpu/drm/xe/xe_guc_submit.c +38 -28

144 lines not on this page · raw message

drivers/gpu/drm/xe/xe_guc_types.h +0 -2
index c7b9642b41ba74..31a2acb63ac34d 100644
@@ -100,8 +100,6 @@ struct xe_guc {
 		 * even initialized - before that not even the lock is valid
 		 */
 		bool initialized;
-		/** @submission_state.fini_wq: submit fini wait queue */
-		wait_queue_head_t fini_wq;
 	} submission_state;
 
 	/** @hwconfig: Hardware config state */
drivers/gpu/drm/xe/xe_module.c +49 -0

67 lines not on this page · raw message

drivers/gpu/drm/xe/xe_module.h +5 -0
index 79cb9639c0f3df..e8e54f701cf3ee 100644
@@ -8,6 +8,8 @@
 
 #include <linux/types.h>
 
+struct work_struct;
+
 /* Module modprobe variables */
 struct xe_modparam {
 	bool force_execlist;
@@ -27,5 +29,8 @@ struct xe_modparam {
 
 extern struct xe_modparam xe_modparam;
 
+bool xe_destroy_wq_queue(struct work_struct *work);
+void xe_destroy_wq_flush(void);
+
 #endif
 
drivers/gpu/drm/xe/xe_pci.c +6 -0
index c2ecd27ec770a2..ad4955fe5ade7e 100644
@@ -1029,6 +1029,12 @@ static void xe_pci_remove(struct pci_dev *pdev)
 		return;
 
 	xe_device_remove(xe);
+
+	/*
+	 * Preserve remove-time flush after moving destroy work to module
+	 * lifetime.
+	 */
+	xe_destroy_wq_flush();
 	xe_pm_fini(xe);
 }
 
Signature · 1 line
2.53.0
author maintainer
#125 lore raw

PATCH 125/744 ksmbd: pin conn during async oplock break notification

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Qihang <[email protected]>

[ Upstream commit aa5d8f3f96aa11a4a54ce993c11ce8af11c546f9 ]

smb2_oplock_break_noti() and smb2_lease_break_noti() store a ksmbd_conn pointer in an async ksmbd_work and then queue that work on ksmbd-io. The work only increments conn->r_count, which prevents teardown from passing the pending-request wait after the increment, but it does not pin the struct ksmbd_conn object.

If connection teardown races with an oplock break notification, the last conn reference can be dropped before the queued worker finishes. The worker then uses the freed conn in ksmbd_conn_write() and ksmbd_conn_r_count_dec().

Take a real conn reference when publishing the conn pointer to the async work item, and drop it after the notification work has decremented r_count. Apply the same lifetime rule to lease break notification, which uses the same work->conn pattern.

Fixes 3aa660c05924 ("ksmbd: prevent connection release during oplock break notification")
---
 fs/smb/server/oplock.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
fs/smb/server/oplock.c +4 -2
index 60e7e821c2455d..3f28dc3b7fc415 100644
@@ -705,6 +705,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
 out:
 	ksmbd_free_work_struct(work);
 	ksmbd_conn_r_count_dec(conn);
+	ksmbd_conn_put(conn);
 }
 
 /**
@@ -740,7 +741,7 @@ static int smb2_oplock_break_noti(struct oplock_info *opinfo)
 	br_info->open_trunc = opinfo->open_trunc;
 
 	work->request_buf = (char *)br_info;
-	work->conn = conn;
+	work->conn = ksmbd_conn_get(conn);
 	work->sess = opinfo->sess;
 
 	ksmbd_conn_r_count_inc(conn);
@@ -814,6 +815,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
 out:
 	ksmbd_free_work_struct(work);
 	ksmbd_conn_r_count_dec(conn);
+	ksmbd_conn_put(conn);
 }
 
 /**
@@ -853,7 +855,7 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)
 	memcpy(br_info->lease_key, lease->lease_key, SMB2_LEASE_KEY_SIZE);
 
 	work->request_buf = (char *)br_info;
-	work->conn = conn;
+	work->conn = ksmbd_conn_get(conn);
 	work->sess = opinfo->sess;
 
 	ksmbd_conn_r_count_inc(conn);
Signature · 1 line
2.53.0
author maintainer
#126 lore raw

PATCH 126/744 ksmbd: validate compound request size before reading StructureSize2

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Xiang Mei (Microsoft) <[email protected]>

[ Upstream commit 15b38176fd1530372905c602fde51fe89ec8c877 ]

When ksmbd validates a compound (chained) SMB2 request, ksmbd_smb2_check_message() reads pdu->StructureSize2 without first checking that the compound element is large enough to contain it. StructureSize2 is a 2-byte field at offset 64 (__SMB2_HEADER_STRUCTURE_SIZE) from the start of each element.

The compound-walking logic only guarantees that a full 64-byte SMB2 header is present for the trailing element: when NextCommand is 0, len is reduced to the number of bytes remaining after next_smb2_rcv_hdr_off. A remote client can craft a compound request whose last element has exactly 64 bytes, so the 2-byte StructureSize2 read at offset 64 extends one byte past the receive buffer, producing a slab-out-of-bounds read.

  BUG: KASAN: slab-out-of-bounds in ksmbd_smb2_check_message (fs/smb/server/smb2misc.c:402)
  Read of size 2 at addr ffff888012ae31ac by task kworker/0:1/14
  The buggy address is located 172 bytes inside of allocated 173-byte region
  Workqueue: ksmbd-io handle_ksmbd_work
  Call Trace:
   ...
   kasan_report (mm/kasan/report.c:595)
   ksmbd_smb2_check_message (fs/smb/server/smb2misc.c:402)
   handle_ksmbd_work (fs/smb/server/server.c:119)
   process_one_work (kernel/workqueue.c:3314)
   worker_thread (kernel/workqueue.c:3397)
   kthread (kernel/kthread.c:436)
   ret_from_fork (arch/x86/kernel/process.c:158)
   ret_from_fork_asm (arch/x86/entry/entry_64.S:245)

Reject any compound element that is too small to hold StructureSize2 before dereferencing it.

Fixes e2f34481b24d ("cifsd: add server-side procedures for SMB3")
Reported-by [email protected]
---
 fs/smb/server/smb2misc.c | 5 +++++
 1 file changed, 5 insertions(+)
fs/smb/server/smb2misc.c +5 -0
index a1ddca21c47bf9..29f33ece30a94e 100644
@@ -399,6 +399,11 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
 		return 1;
 	}
 
+	if (len < __SMB2_HEADER_STRUCTURE_SIZE + sizeof(__le16)) {
+		ksmbd_debug(SMB, "Message is too small for StructureSize2\n");
+		return 1;
+	}
+
 	if (smb2_req_struct_sizes[command] != pdu->StructureSize2) {
 		if (!(command == SMB2_OPLOCK_BREAK_HE &&
 		    (le16_to_cpu(pdu->StructureSize2) == OP_BREAK_STRUCT_SIZE_20 ||
Signature · 1 line
2.53.0
author maintainer
#127 lore raw

PATCH 127/744 drm/i915/wm: clear the plane ddb_y entries on plane disable

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Vinod Govindapillai <[email protected]>

[ Upstream commit e89978c1cff54e265345c66e1177d19ea5a8bc00 ]

The UV/Y plane DDB entriess are never cleared on sk_wm_plane_disable_noatomic() and can leave stale DDB state for NV12 planes on pre-Gen11 devices

Fixes d34b59d5ba41 ("drm/i915: Add skl_wm_plane_disable_noatomic()")
Assisted-by Copilot:claude-sonnet-4.6
(cherry picked from commit 60f68a6ba298fd1e971a2d91576304bee89a16fc)
---
 drivers/gpu/drm/i915/display/skl_watermark.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/i915/display/skl_watermark.c +1 -1
index e0ac4e2ce4dcb6..29b7661f88141d 100644
@@ -3908,7 +3908,7 @@ void skl_wm_plane_disable_noatomic(struct intel_crtc *crtc,
 		return;
 
 	skl_ddb_entry_init(&crtc_state->wm.skl.plane_ddb[plane->id], 0, 0);
-	skl_ddb_entry_init(&crtc_state->wm.skl.plane_ddb[plane->id], 0, 0);
+	skl_ddb_entry_init(&crtc_state->wm.skl.plane_ddb_y[plane->id], 0, 0);
 
 	crtc_state->wm.skl.plane_min_ddb[plane->id] = 0;
 	crtc_state->wm.skl.plane_interim_ddb[plane->id] = 0;
Signature · 1 line
2.53.0
author maintainer
#128 lore raw

PATCH 128/744 drm/i915/selftests: Fix GT PM sort comparators

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Emre Cecanpunar <[email protected]>

[ Upstream commit 612978b83f45bf7018815209db5395d759db6f26 ]

Compare the sampled clock values instead of their addresses. Comparing addresses leaves the samples unsorted, preventing the code from discarding the minimum and maximum samples.

Fixes 1a5392479207 ("drm/i915/selftests: Measure CS_TIMESTAMP")
(cherry picked from commit 682ea2d28d18bb06f9fc663cb5ab7e80dc0e606a)
---
 drivers/gpu/drm/i915/gt/selftest_gt_pm.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/gpu/drm/i915/gt/selftest_gt_pm.c +4 -4
index 33351deeea4f0b..07eaf71955c447 100644
@@ -16,9 +16,9 @@ static int cmp_u64(const void *A, const void *B)
 {
 	const u64 *a = A, *b = B;
 
-	if (a < b)
+	if (*a < *b)
 		return -1;
-	else if (a > b)
+	else if (*a > *b)
 		return 1;
 	else
 		return 0;
@@ -28,9 +28,9 @@ static int cmp_u32(const void *A, const void *B)
 {
 	const u32 *a = A, *b = B;
 
-	if (a < b)
+	if (*a < *b)
 		return -1;
-	else if (a > b)
+	else if (*a > *b)
 		return 1;
 	else
 		return 0;
Signature · 1 line
2.53.0
author maintainer
#129 lore raw

PATCH 129/744 accel/amdxdna: Fix use-after-free of mm_struct in job scheduler

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Lizhi Hou <[email protected]>

[ Upstream commit faebb7ba1ac65fa5810b640df02ce04e509fdc11 ]

amdxdna_cmd_submit() stores current->mm in job->mm without holding any reference. aie2_sched_job_run() later access job->mm from the DRM scheduler worker thread. With only a raw pointer and no structural reference, the mm_struct can be freed before the scheduler runs the job.

Fix this by calling mmgrab() to hold a structural mm_count reference for the lifetime of the job, paired with mmdrop() in every cleanup path.

Fixes aac243092b70 ("accel/amdxdna: Add command execution")
---
 drivers/accel/amdxdna/amdxdna_ctx.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/accel/amdxdna/amdxdna_ctx.c +4 -0
index 5315466f137b55..f6fece060dfedf 100644
@@ -483,6 +483,7 @@ void amdxdna_sched_job_cleanup(struct amdxdna_sched_job *job)
 	amdxdna_arg_bos_put(job);
 	amdxdna_gem_put_obj(job->cmd_bo);
 	dma_fence_put(job->fence);
+	mmdrop(job->mm);
 }
 
 int amdxdna_cmd_submit(struct amdxdna_client *client,
@@ -549,6 +550,7 @@ int amdxdna_cmd_submit(struct amdxdna_client *client,
 
 	job->hwctx = hwctx;
 	job->mm = current->mm;
+	mmgrab(job->mm);
 
 	job->fence = amdxdna_fence_create(hwctx);
 	if (!job->fence) {
@@ -583,6 +585,8 @@ int amdxdna_cmd_submit(struct amdxdna_client *client,
 cmd_put:
 	amdxdna_gem_put_obj(job->cmd_bo);
 free_job:
+	if (job->mm)
+		mmdrop(job->mm);
 	kfree(job);
 	return ret;
 }
Signature · 1 line
2.53.0
author maintainer
#130 lore raw

PATCH 130/744 tcp: fix TIME_WAIT socket reference leak on PSP policy failure

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

[ Upstream commit 2c1931a81122c3cdc4c89448fe0442c69e21c0d5 ]

Release the TIME_WAIT socket reference and jump to discard_it upon PSP policy failure in both IPv4 and IPv6 receive paths. This prevents a memory leak of tcp_tw_bucket structures.

Fixes 659a2899a57d ("tcp: add datapath logic for PSP with inline key exchange")
---
 net/ipv4/tcp_ipv4.c | 6 ++++--
 net/ipv6/tcp_ipv6.c | 6 ++++--
 2 files changed, 8 insertions(+), 4 deletions(-)
net/ipv4/tcp_ipv4.c +4 -2
index bfdabad01fa765..d5cd238358ef04 100644
@@ -2319,8 +2319,10 @@ int tcp_v4_rcv(struct sk_buff *skb)
 		}
 
 		drop_reason = psp_twsk_rx_policy_check(inet_twsk(sk), skb);
-		if (drop_reason)
-			break;
+		if (drop_reason) {
+			inet_twsk_put(inet_twsk(sk));
+			goto discard_it;
+		}
 	}
 		/* to ACK */
 		fallthrough;
net/ipv6/tcp_ipv6.c +4 -2
index 36d75fb50a70b7..71cca3c74423f5 100644
@@ -1962,8 +1962,10 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb)
 		}
 
 		drop_reason = psp_twsk_rx_policy_check(inet_twsk(sk), skb);
-		if (drop_reason)
-			break;
+		if (drop_reason) {
+			inet_twsk_put(inet_twsk(sk));
+			goto discard_it;
+		}
 	}
 		/* to ACK */
 		fallthrough;
Signature · 1 line
2.53.0
author maintainer
#131 lore raw

PATCH 131/744 dpll: fix NULL pointer dereference in dpll_msg_add_pin_ref_sync()

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ivan Vecera <[email protected]>

[ Upstream commit d2e914a4a0d0f753dbae830264850d044026167c ]

When a dpll_pin is shared across multiple dpll_device instances and those devices are being unregistered (e.g. during driver module removal), a NULL pointer dereference can occur in dpll_msg_add_pin_ref_sync().

This happens under the following conditions:
- A pin is registered with two or more dpll devices (dpll_A, dpll_B)
- The pin has ref_sync pairs with other pins
- During unregistration of dpll_A's pins, a ref_sync partner pin is unregistered first, removing it from dpll_A->pin_refs
- But since the partner pin is still registered with dpll_B, its dpll_refs is not empty, so dpll_pin_ref_sync_pair_del() does NOT run and the partner stays in the pin's ref_sync_pins xarray
- When the pin itself is then unregistered from dpll_A, the delete notification calls dpll_msg_add_pin_ref_sync() which finds the partner in ref_sync_pins, passes dpll_pin_available() (partner is still registered with dpll_B), but dpll_pin_on_dpll_priv(dpll_A, partner) returns NULL because partner was already removed from dpll_A->pin_refs
- The NULL priv pointer is passed to the driver's ref_sync_get callback, which dereferences it

 BUG: kernel NULL pointer dereference, address: 0000000000000034
 Oops: Oops: 0000 [#1] SMP NOPTI
 RIP: 0010:zl3073x_dpll_input_pin_ref_sync_get+0x73/0x80 [zl3073x]
 Call Trace:
  dpll_msg_add_pin_ref_sync+0xb8/0x200
  dpll_cmd_pin_get_one+0x3b6/0x4b0
  dpll_pin_event_send+0x72/0x140
  __dpll_pin_unregister+0x5a/0x2b0
  dpll_pin_unregister+0x49/0x70

Fix this by skipping ref_sync pins whose priv pointer cannot be resolved for the current dpll device.

---
 drivers/dpll/dpll_netlink.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/dpll/dpll_netlink.c +3 -0
index 75e3ae0c16d077..8163521188c06c 100644
@@ -557,6 +557,9 @@ dpll_msg_add_pin_ref_sync(struct sk_buff *msg, struct dpll_pin *pin,
 		if (!dpll_pin_available(ref_sync_pin))
 			continue;
 		ref_sync_pin_priv = dpll_pin_on_dpll_priv(dpll, ref_sync_pin);
+		/* Pin may have been unregistered from this dpll already */
+		if (!ref_sync_pin_priv)
+			continue;
 		if (WARN_ON(!ops->ref_sync_get))
 			return -EOPNOTSUPP;
 		ret = ops->ref_sync_get(pin, pin_priv, ref_sync_pin,
Signature · 1 line
2.53.0
author maintainer
#132 lore raw

PATCH 132/744 net/sched: act_tunnel_key: Defer dst_release to RCU callback

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jamal Hadi Salim <[email protected]>

[ Upstream commit f1f5c8a3955f8fda3f84ed883ac8daa1847e724c ]

Fix a race-condition use-after-free in tunnel_key_release_params().

The function releases the metadata_dst of the old params synchronously via dst_release() while deferring the params struct free with kfree_rcu(). A concurrent tunnel_key_act() reader on the datapath may still hold the old params pointer (under rcu_read_lock_bh) and proceed to call dst_clone(&params->tcft_enc_metadata->dst) after the writer's dst_release has already pushed the dst's rcuref to RCUREF_DEAD.

[email protected] produced a poc which i (and Victor) verified that KASAN reports:

==================================================================

BUG: KASAN: slab-use-after-free in instrument_atomic_read_write include/linux/instrumented.h:112
BUG: KASAN: slab-use-after-free in atomic_sub_return_release include/linux/atomic/atomic-instrumented.h:326
BUG: KASAN: slab-use-after-free in __rcuref_put include/linux/rcuref.h:109
BUG: KASAN: slab-use-after-free in rcuref_put include/linux/rcuref.h:173
BUG: KASAN: slab-use-after-free in dst_release+0x5b/0x370 net/core/dst.c:168
Write of size 4 at addr ffff88806158de40 by task poc/9388

CPU: 0 UID: 0 PID: 9388 Comm: poc Tainted: G        W           7.1.0-rc7 #7 PREEMPT(lazy)
Tainted: [W]=WARN
Hardware name: QEMU Ubuntu 25.10 PC v2 (i440FX + PIIX, + 10.1 machine, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
 <TASK>
 __dump_stack lib/dump_stack.c:94
 dump_stack_lvl+0x100/0x190 lib/dump_stack.c:120
 print_address_description mm/kasan/report.c:378
 print_report+0x139/0x4ad mm/kasan/report.c:482
 kasan_report+0xe4/0x1d0 mm/kasan/report.c:595
 check_region_inline mm/kasan/generic.c:186
 kasan_check_range+0x125/0x200 mm/kasan/generic.c:200
 instrument_atomic_read_write include/linux/instrumented.h:112
 atomic_sub_return_release include/linux/atomic/atomic-instrumented.h:326
 __rcuref_put include/linux/rcuref.h:109
 rcuref_put include/linux/rcuref.h:173
 dst_release+0x5b/0x370 net/core/dst.c:168
 refdst_drop include/net/dst.h:272
 skb_dst_drop include/net/dst.h:284
 skb_release_head_state+0x293/0x400 net/core/skbuff.c:1163
 skb_release_all net/core/skbuff.c:1187
[..]
Allocated by task 9391:
 kasan_save_stack+0x30/0x50 mm/kasan/common.c:57
 kasan_save_track+0x14/0x30 mm/kasan/common.c:78
 poison_kmalloc_redzone mm/kasan/common.c:398
 __kasan_kmalloc+0x9a/0xb0 mm/kasan/common.c:415
 kasan_kmalloc include/linux/kasan.h:263
 __do_kmalloc_node mm/slub.c:5296
 __kmalloc_noprof+0x2f1/0x830 mm/slub.c:5308
 kmalloc_noprof include/linux/slab.h:954
 kzalloc_noprof include/linux/slab.h:1188
 offload_action_alloc+0x2f/0x130 net/core/flow_offload.c:35
 tcf_action_offload_add_ex+0x1ba/0x880 net/sched/act_api.c:258
 tcf_action_offload_add net/sched/act_api.c:293
 tcf_action_init+0x66e/0xa20 net/sched/act_api.c:1547
 tcf_action_add+0xf6/0x5d0 net/sched/act_api.c:2101
[..]
Freed by task 9391:
 kasan_save_stack+0x30/0x50 mm/kasan/common.c:57
 kasan_save_track+0x14/0x30 mm/kasan/common.c:78
 kasan_save_free_info+0x3b/0x70 mm/kasan/generic.c:584
 poison_slab_object mm/kasan/common.c:253
 __kasan_slab_free+0x6b/0x90 mm/kasan/common.c:285
 kasan_slab_free include/linux/kasan.h:235
 slab_free_hook mm/slub.c:2689
 slab_free mm/slub.c:6251
 kfree+0x21f/0x6b0 mm/slub.c:6566
 tcf_action_offload_add_ex+0x4ad/0x880 net/sched/act_api.c:284
 tcf_action_offload_add net/sched/act_api.c:293
 tcf_action_init+0x66e/0xa20 net/sched/act_api.c:1547
 tcf_action_add+0xf6/0x5d0 net/sched/act_api.c:2101

The buggy address belongs to the object at ffff88806158de00
 which belongs to the cache kmalloc-256 of size 256

The buggy address is located 64 bytes inside of
freed 256-byte region [ffff88806158de00, ffff88806158df00)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff88806158d600 pfn:0x6158c
head: order:1 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x4fff00000000240(workingset|head|node=1|zone=1|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 04fff00000000240 ffff88801c841b40 ffffea0001856290 ffffea0001856190
raw: ffff88806158d600 0000000800100009 00000000f5000000 0000000000000000

head: 04fff00000000240 ffff88801c841b40 ffffea0001856290 ffffea0001856190
head: ffff88806158d600 0000000800100009 00000000f5000000 0000000000000000
head: 04fff00000000001 ffffffffffffff81 00000000ffffffff 00000000ffffffff
head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000002

page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 1, migratetype Unmovable, gfp_mask 0xd2820(GFP_ATOMIC|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 9391, tgid 9378 (poc), ts 123227323196, free_ts 0
 set_page_owner include/linux/page_owner.h:32
 post_alloc_hook+0xfe/0x140 mm/page_alloc.c:1853
 prep_new_page mm/page_alloc.c:1861
 get_page_from_freelist+0x110c/0x2fc0 mm/page_alloc.c:3941
 __alloc_frozen_pages_noprof+0x263/0x2bc0 mm/page_alloc.c:5221
 alloc_slab_page mm/slub.c:3278
 allocate_slab mm/slub.c:3467
 new_slab+0xa6/0x690 mm/slub.c:3525
 refill_objects+0x271/0x420 mm/slub.c:7272
 refill_sheaf mm/slub.c:2816
 __pcs_replace_empty_main+0x373/0x630 mm/slub.c:4652
 alloc_from_pcs mm/slub.c:4750
 slab_alloc_node mm/slub.c:4884
 __do_kmalloc_node mm/slub.c:5295
 __kmalloc_noprof+0x66d/0x830 mm/slub.c:5308
 kmalloc_noprof include/linux/slab.h:954
 metadata_dst_alloc+0x26/0x90 net/core/dst.c:298
 tun_rx_dst include/net/dst_metadata.h:144
 __ip_tun_set_dst include/net/dst_metadata.h:208
 tunnel_key_init+0xb01/0x1b90 net/sched/act_tunnel_key.c:451
 tcf_action_init_1+0x46b/0x6c0 net/sched/act_api.c:1428
 tcf_action_init+0x448/0xa20 net/sched/act_api.c:1503
 tcf_action_add+0xf6/0x5d0 net/sched/act_api.c:2101

[..]
==================================================================

Fix by moving dst_release() into a custom RCU callback that runs after the grace period, matching the lifetime of the containing params struct. Readers in the datapath therefore always find a live rcuref when calling dst_clone().

Fixes 9174c3df1cd18 ("net/sched: act_tunnel_key: fix memory leak in case of action replace")
Reported-by [email protected]
---
 net/sched/act_tunnel_key.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)
net/sched/act_tunnel_key.c +10 -4
index 876b30c5709e1f..b14807761d829e 100644
@@ -342,14 +342,20 @@ static const struct nla_policy tunnel_key_policy[TCA_TUNNEL_KEY_MAX + 1] = {
 	[TCA_TUNNEL_KEY_ENC_TTL]      = { .type = NLA_U8 },
 };
 
-static void tunnel_key_release_params(struct tcf_tunnel_key_params *p)
+static void tunnel_key_release_params_rcu(struct rcu_head *head)
 {
-	if (!p)
-		return;
+	struct tcf_tunnel_key_params *p = container_of(head, typeof(*p), rcu);
+
 	if (p->tcft_action == TCA_TUNNEL_KEY_ACT_SET)
 		dst_release(&p->tcft_enc_metadata->dst);
+	kfree(p);
+}
 
-	kfree_rcu(p, rcu);
+static void tunnel_key_release_params(struct tcf_tunnel_key_params *p)
+{
+	if (!p)
+		return;
+	call_rcu(&p->rcu, tunnel_key_release_params_rcu);
 }
 
 static int tunnel_key_init(struct net *net, struct nlattr *nla,
Signature · 1 line
2.53.0
author maintainer
#133 lore raw

PATCH 133/744 sctp: fix auth_hmacs array size in struct sctp_cookie

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Xin Long <[email protected]>

[ Upstream commit e0b5252a59383b77d1b8dbeda00b7184dd95f4d3 ]

The auth_hmacs array in struct sctp_cookie is supposed to store a complete SCTP_AUTH_HMAC_ALGO parameter, which consists of a struct sctp_paramhdr followed by N HMAC identifiers.

However, the array size was calculated using an extra 2 bytes instead of sizeof(struct sctp_paramhdr), which is 4 bytes. When four HMAC identifiers are configured, the HMAC-ALGO parameter stored in the endpoint is larger than the auth_hmacs buffer in the cookie.

As a result, sctp_association_init() copies beyond the end of auth_hmacs when initializing the association, corrupting the adjacent auth_chunks field. This can lead to an invalid HMAC identifier being accepted and later cause an out-of-bounds read in sctp_auth_get_hmac().

Fix the array size calculation by including the full SCTP parameter header size.

---
 include/net/sctp/structs.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
include/net/sctp/structs.h +2 -1
index affee44bd38e31..cccc662561aac3 100644
@@ -312,7 +312,8 @@ struct sctp_cookie {
 
 	__u8 auth_random[sizeof(struct sctp_paramhdr) +
 			 SCTP_AUTH_RANDOM_LENGTH];
-	__u8 auth_hmacs[SCTP_AUTH_NUM_HMACS * sizeof(__u16) + 2];
+	__u8 auth_hmacs[sizeof(struct sctp_paramhdr) +
+			SCTP_AUTH_NUM_HMACS * sizeof(__u16)];
 	__u8 auth_chunks[sizeof(struct sctp_paramhdr) + SCTP_AUTH_MAX_CHUNKS];
 
 	/* This is a shim for my peer's INIT packet, followed by
Signature · 1 line
2.53.0
author maintainer
#134 lore raw

PATCH 134/744 bnxt_en: Handle partially initialized auxiliary devices

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ruoyu Wang <[email protected]>

[ Upstream commit 1cb8553c02e93e5a150cebd42f9ee3db0ece4707 ]

bnxt_aux_devices_init() calls auxiliary_device_init() before all fields used by bnxt_aux_dev_release() are initialized. After auxiliary_device_init() succeeds, later errors must unwind with auxiliary_device_uninit(), which invokes the release callback.

The release callback assumes that aux_priv->id, aux_priv->edev, edev->net and edev->ulp_tbl are all populated. If allocation fails after auxiliary_device_init(), the release path can otherwise dereference or clear partially initialized state.

Allocate and attach the bnxt_en_dev and ULP table before calling auxiliary_device_init(), so the release callback only sees a fully initialized auxiliary private object. If auxiliary_device_init() itself fails, free those allocations directly because device_initialize() has not run and the release callback will not be invoked.

This issue was found by a static analysis checker and confirmed by manual source review.

Fixes 194fad5b2781 ("bnxt_en: Refactor bnxt_rdma_aux_device_init/uninit functions")
---
 drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | 39 ++++++++++---------
 1 file changed, 20 insertions(+), 19 deletions(-)
drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +20 -19
index 5c751933da6a9d..a515c368bac015 100644
@@ -566,6 +566,18 @@ void bnxt_aux_devices_init(struct bnxt *bp)
 		if (!aux_priv)
 			goto next_auxdev;
 
+		edev = kzalloc_obj(*edev);
+		if (!edev)
+			goto aux_priv_free;
+		aux_priv->edev = edev;
+		bnxt_set_edev_info(edev, bp);
+
+		ulp = kzalloc_obj(*ulp);
+		if (!ulp)
+			goto edev_free;
+		edev->ulp_tbl = ulp;
+		aux_priv->id = idx;
+
 		aux_dev = &aux_priv->aux_dev;
 		aux_dev->id = bp->auxdev_id;
 		aux_dev->name = bnxt_aux_devices[idx].name;
@@ -573,37 +585,26 @@ void bnxt_aux_devices_init(struct bnxt *bp)
 		aux_dev->dev.release = bnxt_aux_dev_release;
 
 		rc = auxiliary_device_init(aux_dev);
-		if (rc) {
-			kfree(aux_priv);
-			goto next_auxdev;
-		}
+		if (rc)
+			goto ulp_free;
 		bp->aux_priv[idx] = aux_priv;
 
 		/* From this point, all cleanup will happen via the .release
 		 * callback & any error unwinding will need to include a call
 		 * to auxiliary_device_uninit.
 		 */
-		edev = kzalloc_obj(*edev);
-		if (!edev)
-			goto aux_dev_uninit;
-
-		aux_priv->edev = edev;
-		bnxt_set_edev_info(edev, bp);
-
-		ulp = kzalloc_obj(*ulp);
-		if (!ulp)
-			goto aux_dev_uninit;
-
-		edev->ulp_tbl = ulp;
 		bp->edev[idx] = edev;
 		if (idx == BNXT_AUXDEV_RDMA)
 			bp->ulp_num_msix_want = bnxt_set_dflt_ulp_msix(bp);
-		aux_priv->id = idx;
 		bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_INIT);
 
 		continue;
-aux_dev_uninit:
-		auxiliary_device_uninit(aux_dev);
+ulp_free:
+		kfree(ulp);
+edev_free:
+		kfree(edev);
+aux_priv_free:
+		kfree(aux_priv);
 next_auxdev:
 		if (idx == BNXT_AUXDEV_RDMA)
 			bp->flags &= ~BNXT_FLAG_ROCE_CAP;
Signature · 1 line
2.53.0
author maintainer
#135 lore raw

PATCH 135/744 selftests: netconsole: only restore MAC when it changed on resume

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Andre Carvalho <[email protected]>

[ Upstream commit 04aeddf2dadd0eb7ad016a766dcbe9c983311f09 ]

The "mac" bind mode reactivation downs the interface, restores the saved MAC and renames it to trigger a target resume. This assumes the recreated interface comes back with a different MAC, which is true under MACAddressPolicy=none (as on the Netdev CI) but not when MACs are persistent. In the persistent case netconsole resumes the target on its own, and the down/restore/rename flow instead drops it and fails the test.

Guard the block on the MAC having actually changed so the test passes under both policies.

---
 .../testing/selftests/drivers/net/netconsole/netcons_resume.sh | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
tools/testing/selftests/drivers/net/netconsole/netcons_resume.sh +2 -1
index cb59cf436dd0a3..d9111f2102bcd1 100755
@@ -44,7 +44,8 @@ function trigger_reactivation() {
 	# Restore MACs
 	ip netns exec "${NAMESPACE}" ip link set "${DSTIF}" \
 		address "${SAVED_DSTMAC}"
-	if [ "${BINDMODE}" == "mac" ]; then
+	if [ "${BINDMODE}" == "mac" ] &&
+		[ "$(mac_get "${SRCIF}")" != "${SAVED_SRCMAC}" ]; then
 		ip link set dev "${SRCIF}" down
 		ip link set dev "${SRCIF}" address "${SAVED_SRCMAC}"
 		# Rename device in order to trigger target resume, as initial
Signature · 1 line
2.53.0
author maintainer
#136 lore raw

PATCH 136/744 mpls: fix NULL deref in mpls_valid_fib_dump_req() on CONFIG_INET=n

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Weiming Shi <[email protected]>

[ Upstream commit 56d96fededd61192cd7cc8d2b0f36adfd59036c3 ]

On CONFIG_INET=n builds, mpls_valid_fib_dump_req() walks the parsed attribute table itself instead of calling ip_valid_fib_dump_req(). The RTA_OIF arm passes tb[RTA_OIF] to nla_get_u32() without checking it is present, so an RTM_GETROUTE dump for AF_MPLS with strict checking and no RTA_OIF hits a NULL dereference.

RTM_GETROUTE is RTNL_KIND_GET, which rtnetlink_rcv_msg() permits without CAP_NET_ADMIN, so an unprivileged user can trigger it.

  Oops: general protection fault, probably for non-canonical address
        0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI
  KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
  RIP: 0010:mpls_valid_fib_dump_req (net/mpls/af_mpls.c:2189)
  Call Trace:
   mpls_dump_routes (net/mpls/af_mpls.c:2236)
   netlink_dump (net/netlink/af_netlink.c:2331)
   __netlink_dump_start (net/netlink/af_netlink.c:2446)
   rtnetlink_rcv_msg (net/core/rtnetlink.c:7033)
   netlink_rcv_skb (net/netlink/af_netlink.c:2556)
   netlink_unicast (net/netlink/af_netlink.c:1345)
   netlink_sendmsg (net/netlink/af_netlink.c:1900)
   __sock_sendmsg (net/socket.c:790)
   ____sys_sendmsg (net/socket.c:2684)
   ___sys_sendmsg (net/socket.c:2738)
   __sys_sendmsg (net/socket.c:2770)
   do_syscall_64 (arch/x86/entry/syscall_64.c:94)
   entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)

Skip unset attributes, as ip_valid_fib_dump_req() does.

Fixes 196cfebf8972 ("net/mpls: Handle kernel side filtering of route dumps")
Assisted-by Claude:claude-opus-4-8
---
 net/mpls/af_mpls.c | 3 +++
 1 file changed, 3 insertions(+)
net/mpls/af_mpls.c +3 -0
index 26340a7306b591..b64a8b1bac0961 100644
@@ -2186,6 +2186,9 @@ static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
 		int ifindex;
 
 		if (i == RTA_OIF) {
+			if (!tb[i])
+				continue;
+
 			ifindex = nla_get_u32(tb[i]);
 			filter->dev = dev_get_by_index_rcu(net, ifindex);
 			if (!filter->dev)
Signature · 1 line
2.53.0
author maintainer
#137 lore raw

PATCH 137/744 usb: core: sysfs: add lock to bos_descriptors_read()

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Griffin Kroah-Hartman <[email protected]>

commit 4e0197fbb0eec588795d5431716a244d9ac8fa93 upstream.

Add a lock to the function bos_descriptors_read().

This function accesses udev->bos, which could be simultaneously freed in usb_reset_and_verify_device(), a function that is commonly called in drivers all over the kernel.

---
 drivers/usb/core/sysfs.c |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/usb/core/sysfs.c +7 -1
@@ -899,10 +899,15 @@ bos_descriptors_read(struct file *filp,
 {
 	struct device *dev = kobj_to_dev(kobj);
 	struct usb_device *udev = to_usb_device(dev);
-	struct usb_host_bos *bos = udev->bos;
+	struct usb_host_bos *bos;
 	struct usb_bos_descriptor *desc;
 	size_t desclen, n = 0;
+	int rc;
 
+	rc = usb_lock_device_interruptible(udev);
+	if (rc < 0)
+		return -EINTR;
+	bos = udev->bos;
 	if (bos) {
 		desc = bos->desc;
 		desclen = le16_to_cpu(desc->wTotalLength);
@@ -911,6 +916,7 @@ bos_descriptors_read(struct file *filp,
 			memcpy(buf, (void *) desc + off, n);
 		}
 	}
+	usb_unlock_device(udev);
 	return n;
 }
 static const BIN_ATTR_RO(bos_descriptors, 65535); /* max-size BOS */
author maintainer
#138 lore raw

PATCH 138/744 wifi: at76c50x-usb: avoid length underflow in at76_guess_freq()

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Huihui Huang <[email protected]>

commit 61a799ffd1e5a4fd3702d547828b7ff3d161468e upstream.

at76_guess_freq() checks only that the received frame is at least a bare 802.11 header (24 bytes) before subtracting the fixed management-body offset:

	len -= el_off;

For both beacon and probe response frames, el_off is 36. If the frame is shorter than el_off, subtracting it causes the calculated IE length to wrap. The length is eventually passed to cfg80211_find_elem_match() as a very large unsigned value, so the element walk runs beyond the RX skb.

This path is reached from at76_rx_tasklet() while scanning. If the device delivers a truncated beacon or probe response, the oversized IE length causes an out-of-bounds read during scanning.

Skip the IE lookup if the frame does not reach the variable elements, before subtracting el_off.

Fixes 1264b951463a ("at76c50x-usb: add driver")
Assisted-by Claude:claude-opus-4-8
---
 drivers/net/wireless/atmel/at76c50x-usb.c |    7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/net/wireless/atmel/at76c50x-usb.c +5 -2
@@ -1521,13 +1521,16 @@ static inline int at76_guess_freq(struct
 
 	if (ieee80211_is_probe_resp(hdr->frame_control)) {
 		el_off = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
-		el = ((struct ieee80211_mgmt *)hdr)->u.probe_resp.variable;
 	} else if (ieee80211_is_beacon(hdr->frame_control)) {
 		el_off = offsetof(struct ieee80211_mgmt, u.beacon.variable);
-		el = ((struct ieee80211_mgmt *)hdr)->u.beacon.variable;
 	} else {
 		goto exit;
 	}
+
+	if (len < el_off)
+		goto exit;
+
+	el = priv->rx_skb->data + el_off;
 	len -= el_off;
 
 	el = cfg80211_find_ie(WLAN_EID_DS_PARAMS, el, len);
author maintainer
#139 lore raw

PATCH 139/744 usb: core: port: Deattach Type-C connector on component unbind

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Chia-Lin Kao (AceLan) <[email protected]>

commit e0b291fe117964037e0ba382eff4bb365d531c3a upstream.

connector_unbind() is the mirror of connector_bind(), but it is missing the symmetric call to typec_deattach() that connector_bind() makes via:

    if (port_dev->child)
        typec_attach(port_dev->connector, &port_dev->child->dev);

When a Thunderbolt dock is unplugged, two teardown paths race:

1. The component framework calls connector_unbind() first, which sets port_dev->connector = NULL without calling typec_deattach(). This leaves port->usb2_dev/port->usb3_dev in struct typec_port pointing at the USB device that is about to be freed.

2. usb_disconnect() then calls typec_deattach(port_dev->connector, ...), but port_dev->connector is already NULL, so the call is a no-op and port->usb2_dev is never cleared.

3. Concurrently, UCSI detects a PD partner-disconnect event and calls typec_unregister_partner(), which reads port->usb2_dev (now a dangling pointer to freed memory) and passes it to typec_partner_unlink_device() -> sysfs_remove_link() -> dev_name() on the freed device, corrupting the typec/UCSI partner state.

This corruption leaves the Thunderbolt tunnel in an inconsistent state on the next dock hot-plug. On affected hardware the dock's I225/igc NIC fails to enumerate: AER fires a slot reset while the igc driver is still initialising ("PCIe link lost"), and the subsequent igc_reset attempt hits igc_rd32 on an already-detached device:

    igc 0000:2e:00.0 eth0: PCIe link lost, device now detached
    igc: Failed to read reg 0x0!
    WARNING: CPU: 9 PID: 129 at drivers/net/ethernet/intel/igc/igc_main.c:7005
             igc_rd32+0xa4/0xc0 [igc]
    Call Trace:
     igc_disable_pcie_master+0x16/0xa0 [igc]
     igc_reset_hw_base+0x14/0x170 [igc]
     igc_reset+0x63/0x110 [igc]
     igc_io_slot_reset+0x9e/0xd0 [igc]
     report_slot_reset+0x5d/0xc0
     pcie_do_recovery+0x209/0x400
     aer_isr_one_error_type+0x235/0x430
     aer_isr+0x4e/0x80
     irq_thread+0xf4/0x1f0

4. UCSI later handles the PD partner-disconnect and calls typec_unregister_partner(), which still sees the stale port->usb2_dev and tries to remove its sysfs link a second time:

kernfs: can not remove 'typec', no directory

   WARNING: CPU: 6 PID: 55 at fs/kernfs/dir.c:1706 kernfs_remove_by_name_ns+0xe9/0xf0
   Workqueue: events ucsi_handle_connector_change [typec_ucsi]
   Call Trace:
    sysfs_remove_link+0x19/0x50
    typec_unregister_partner+0x6e/0x120 [typec]
    ucsi_unregister_partner+0x107/0x150 [typec_ucsi]
    ucsi_handle_connector_change+0x3ec/0x490 [typec_ucsi]
    process_one_work+0x18e/0x3e0
    worker_thread+0x2e3/0x420
    kthread+0x10a/0x230
    ret_from_fork+0x121/0x140
    ret_from_fork_asm+0x1a/0x30

With worse timing the same stale pointer is dereferenced after the backing memory is freed, turning the warning into a use-after-free.

Fix the asymmetry: call typec_deattach() before clearing port_dev->connector, matching what connector_bind() does on the bind side. typec_partner_deattach() is already protected by port->partner_link_lock, so it serialises safely with the concurrent typec_unregister_partner() path.

Fixes 11110783f5ea ("usb: Inform the USB Type-C class about enumerated devices")
Cc stable <[email protected]>
---
 drivers/usb/core/port.c |    2 ++
 1 file changed, 2 insertions(+)
drivers/usb/core/port.c +2 -0
@@ -740,6 +740,8 @@ static void connector_unbind(struct devi
 
 	sysfs_remove_link(&connector->kobj, dev_name(dev));
 	sysfs_remove_link(&dev->kobj, "connector");
+	if (port_dev->child)
+		typec_deattach(port_dev->connector, &port_dev->child->dev);
 	port_dev->connector = NULL;
 }
 
author maintainer
#140 lore raw

PATCH 140/744 usb: musb: omap2430: Do not put borrowed of_node in probe

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Guangshuo Li <[email protected]>

commit c947360ae63eee1c9eacc030dd6f5a53f717addf upstream.

omap2430_probe() stores pdev->dev.of_node in a local np variable. This is a borrowed pointer and the probe function does not take a reference to it.

The success and error paths nevertheless call of_node_put(np). This drops a reference that is owned by the platform device, and can leave pdev->dev.of_node with an unbalanced reference count.

Do not put the borrowed platform device node from omap2430_probe(). References taken for the child MUSB device are handled by the device core, and the ctrl-module phandle reference is still released separately.

Fixes ffbe2feac59b ("usb: musb: omap2430: Fix probe regression for missing resources")
Cc stable <[email protected]>
---
 drivers/usb/musb/omap2430.c |    2 --
 1 file changed, 2 deletions(-)
drivers/usb/musb/omap2430.c +0 -2
@@ -454,7 +454,6 @@ static int omap2430_probe(struct platfor
 		dev_err(&pdev->dev, "failed to register musb device\n");
 		goto err_disable_rpm;
 	}
-	of_node_put(np);
 
 	return 0;
 
@@ -464,7 +463,6 @@ err_put_control_otghs:
 	if (!IS_ERR(glue->control_otghs))
 		put_device(glue->control_otghs);
 err_put_musb:
-	of_node_put(np);
 	platform_device_put(musb);
 
 	return ret;
author maintainer
#141 lore raw

PATCH 141/744 USB: storage: add NO_ATA_1X quirk for Longmai USB Key

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Huang Wei <[email protected]>

commit 3b4ca2e01c1dd8c00b675b794732945f460a471b upstream.

The Longmai Technologies USB Key (0x04b4:0xb708) advertises itself as a SCSI/Bulk-only mass storage device but does not correctly handle ATA pass-through commands. When such a command (ATA_12 or ATA_16) is sent to the device it fails to respond and the transfer eventually times out, leaving the device unusable.

Add an unusual_devs entry for this device that sets the US_FL_NO_ATA_1X flag, so usb-storage short-circuits ATA pass-through commands and returns INVALID COMMAND OPERATION CODE (0x20 0x05 0x24 0x00) instead of forwarding them to the device.

Information about the device in /sys/kernel/debug/usb/devices:

T:  Bus=02 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 12 Spd=480  MxCh= 0
D:  Ver= 2.00 Cls=00(>ifc ) Sub=06 Prot=50 MxPS=64 #Cfgs=  1
P:  Vendor=04b4 ProdID=b708 Rev= 1.00
S:  Manufacturer=Longmai Technologies
S:  Product=USB Key
C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage
E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
---
 drivers/usb/storage/unusual_devs.h |    7 +++++++
 1 file changed, 7 insertions(+)
drivers/usb/storage/unusual_devs.h +7 -0
@@ -395,6 +395,13 @@ UNUSUAL_DEV(  0x04b3, 0x4001, 0x0110, 0x
 		USB_SC_DEVICE, USB_PR_CB, NULL,
 		US_FL_MAX_SECTORS_MIN),
 
+/* Reported by Ai Chao <[email protected]> */
+UNUSUAL_DEV(  0x04b4, 0xb708, 0x0000, 0xffff,
+		"Longmai Technologies",
+		"USB Key",
+		USB_SC_SCSI, USB_PR_BULK, NULL,
+		US_FL_NO_ATA_1X),
+
 /*
  * Reported by Simon Levitt <[email protected]>
  * This entry needs Sub and Proto fields
author maintainer
#142 lore raw

PATCH 142/744 usb: chipidea: fix usage_count leak when autosuspend_delay is negative

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Xu Yang <[email protected]>

commit fc3afb5728e297994863f8a2a01b88a920bbf53e upstream.

The probe() calls pm_runtime_use_autosuspend(), but remove() does not call pm_runtime_dont_use_autosuspend(). This can lead to a usage_count leak if autosuspend_delay is set to a negative value.

The pm_runtime_use_autosuspend() also notes that it's important to undo this with pm_runtime_dont_use_autosuspend() at driver exit time.

Fixes 1f874edcb731 ("usb: chipidea: add runtime power management support")
Cc stable <[email protected]>
Assisted-by Claude:claude-sonnet-4.6
---
 drivers/usb/chipidea/core.c |    1 +
 1 file changed, 1 insertion(+)
drivers/usb/chipidea/core.c +1 -0
@@ -1253,6 +1253,7 @@ static void ci_hdrc_remove(struct platfo
 		usb_role_switch_unregister(ci->role_switch);
 
 	if (ci->supports_runtime_pm) {
+		pm_runtime_dont_use_autosuspend(&pdev->dev);
 		pm_runtime_get_sync(&pdev->dev);
 		pm_runtime_disable(&pdev->dev);
 		pm_runtime_put_noidle(&pdev->dev);
author maintainer
#143 lore raw

PATCH 143/744 usb: gadget: dummy_hcd: prevent fifo_req reuse during giveback

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jinchao Wang <[email protected]>

commit d5e5cd3654d2b5359a12ea6586120f05b28634ee upstream.

dummy_hcd embeds a single shared usb_request (dum->fifo_req) that the "emulated single-request FIFO" fast-path in dummy_queue() reuses for small IN transfers: it copies the caller's request into it (req->req = *_req) and queues it, treating list_empty(&fifo_req.queue) as "the slot is free".

The completion side (dummy_timer/transfer/nuke/dummy_dequeue) follows the standard pattern: list_del_init(&req->queue) unlinks the request, then the lock is dropped and usb_gadget_giveback_request() invokes req->complete(). But list_del_init() makes fifo_req.queue look empty *before* the completion callback returns, so a concurrent dummy_queue() on another CPU sees the slot as free, reuses fifo_req and runs req->req = *_req -- overwriting req->complete while dummy_timer is mid-calling it. The indirect call then jumps to a clobbered pointer, causing a general protection fault / page fault in dummy_timer (syzkaller extid faf3a6cf579fc65591ca). The clobbering write is an in-bounds memcpy on a live shared object, so KASAN cannot flag it.

Add a fifo_req_busy bit covering the shared request's whole lifetime:
set it in dummy_queue() when the FIFO fast-path takes fifo_req (making it the fast-path guard, replacing the list_empty(&fifo_req.queue) test), and clear it after the completion callback has returned, via a dummy_giveback() helper used at all four gadget-request giveback sites. The shared slot can no longer be reused until its completion callback has finished.

---
 drivers/usb/gadget/udc/dummy_hcd.c |   40 ++++++++++++++++++++++++-------------
 1 file changed, 27 insertions(+), 13 deletions(-)
drivers/usb/gadget/udc/dummy_hcd.c +27 -13
@@ -278,6 +278,7 @@ struct dummy {
 	unsigned			ints_enabled:1;
 	unsigned			udc_suspended:1;
 	unsigned			pullup:1;
+	unsigned			fifo_req_busy:1;
 
 	/*
 	 * HOST side support
@@ -329,6 +330,26 @@ static inline struct dummy *gadget_dev_t
 
 /* DEVICE/GADGET SIDE UTILITY ROUTINES */
 
+/*
+ * Give back a gadget request with dum->lock dropped around the callback.
+ * If @req is the shared fifo_req, clear fifo_req_busy afterward: the flag
+ * was set in dummy_queue() when the shared request was taken and must stay
+ * set until its completion callback has returned; list_del_init() alone
+ * makes the request look idle while the callback is still running.
+ * Caller holds dum->lock and has already done list_del_init() + status.
+ */
+static void dummy_giveback(struct dummy *dum, struct usb_ep *_ep,
+			   struct dummy_request *req)
+{
+	bool fifo = req == &dum->fifo_req;
+
+	spin_unlock(&dum->lock);
+	usb_gadget_giveback_request(_ep, &req->req);
+	spin_lock(&dum->lock);
+	if (fifo)
+		dum->fifo_req_busy = 0;
+}
+
 /* called with spinlock held */
 static void nuke(struct dummy *dum, struct dummy_ep *ep)
 {
@@ -339,9 +360,7 @@ static void nuke(struct dummy *dum, stru
 		list_del_init(&req->queue);
 		req->req.status = -ESHUTDOWN;
 
-		spin_unlock(&dum->lock);
-		usb_gadget_giveback_request(&ep->ep, &req->req);
-		spin_lock(&dum->lock);
+		dummy_giveback(dum, &ep->ep, req);
 	}
 }
 
@@ -728,10 +747,11 @@ static int dummy_queue(struct usb_ep *_e
 
 	/* implement an emulated single-request FIFO */
 	if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
-			list_empty(&dum->fifo_req.queue) &&
+			!dum->fifo_req_busy &&
 			list_empty(&ep->queue) &&
 			_req->length <= FIFO_SIZE) {
 		req = &dum->fifo_req;
+		dum->fifo_req_busy = 1;
 		req->req = *_req;
 		req->req.buf = dum->fifo_buf;
 		memcpy(dum->fifo_buf, _req->buf, _req->length);
@@ -785,9 +805,7 @@ static int dummy_dequeue(struct usb_ep *
 		dev_dbg(udc_dev(dum),
 				"dequeued req %p from %s, len %d buf %p\n",
 				req, _ep->name, _req->length, _req->buf);
-		spin_unlock(&dum->lock);
-		usb_gadget_giveback_request(_ep, _req);
-		spin_lock(&dum->lock);
+		dummy_giveback(dum, _ep, req);
 	}
 	spin_unlock_irqrestore(&dum->lock, flags);
 	return retval;
@@ -1523,9 +1541,7 @@ top:
 		if (req->req.status != -EINPROGRESS) {
 			list_del_init(&req->queue);
 
-			spin_unlock(&dum->lock);
-			usb_gadget_giveback_request(&ep->ep, &req->req);
-			spin_lock(&dum->lock);
+			dummy_giveback(dum, &ep->ep, req);
 
 			/* requests might have been unlinked... */
 			rescan = 1;
@@ -1910,9 +1926,7 @@ restart:
 				dev_dbg(udc_dev(dum), "stale req = %p\n",
 						req);
 
-				spin_unlock(&dum->lock);
-				usb_gadget_giveback_request(&ep->ep, &req->req);
-				spin_lock(&dum->lock);
+				dummy_giveback(dum, &ep->ep, req);
 				ep->already_seen = 0;
 				goto restart;
 			}
author maintainer
#144 lore raw

PATCH 144/744 usb: gadget: f_midi: cancel pending IN work before freeing the midi object

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Fan Wu <[email protected]>

commit 5650c18d93a1db7e27cb5a40b394747eb4686d5b upstream.

The f_midi driver embeds a work item (midi->work) whose handler, f_midi_in_work(), dereferences the enclosing struct f_midi through container_of(). This work is armed from two sites: f_midi_complete(), on a normal IN-endpoint completion, and f_midi_in_trigger(), on an ALSA rawmidi output-stream start.

Neither f_midi_disable() nor f_midi_unbind() cancels midi->work. f_midi_disable() only disables the endpoints and drains the in_req_fifo; it does not synchronize the work item, and the sound card is released asynchronously to the final free of the midi object.

The midi object is reference-counted (midi->free_ref) and is freed in f_midi_free() only once both the usb_function reference and the rawmidi private_data reference have been dropped. In f_midi_unbind(), f_midi_disable() runs before the sound card is released, so while the USB endpoints are already disabled the rawmidi device is still usable by an open substream. A concurrent userspace write on such a substream can reach f_midi_in_trigger() and queue midi->work again after f_midi_disable() has returned. A work item armed this way may still be pending when the last reference drops and f_midi_free() proceeds to kfree(midi), letting f_midi_in_work() dereference the struct after it has been freed, a use-after-free.

For this reason cancelling midi->work in f_midi_disable() would not be
sufficient: the ALSA trigger path can rearm the work after disable() returns. Cancelling at the refcount-zero free site is the boundary after which neither arming source can survive, because by then both references that keep the midi object alive have been dropped: the USB endpoints are already disabled and the rawmidi device has been released.

Fix this by calling cancel_work_sync(&midi->work) in the refcount-zero block of f_midi_free(), before the embedded work_struct is freed along with the rest of the structure. opts->lock is a sleeping mutex, so calling cancel_work_sync() under it is permitted, and the handler takes midi->transmit_lock rather than opts->lock, so no self-deadlock can occur while it waits for a running instance of the work to finish.

This issue was found by an in-house static analysis tool.

Fixes 8653d71ce3763 ("usb/gadget: f_midi: Replace tasklet with work")
Cc stable <[email protected]>
Assisted-by Codex:gpt-5.5
---
 drivers/usb/gadget/function/f_midi.c |    1 +
 1 file changed, 1 insertion(+)
drivers/usb/gadget/function/f_midi.c +1 -0
@@ -1309,6 +1309,7 @@ static void f_midi_free(struct usb_funct
 	opts = container_of(f->fi, struct f_midi_opts, func_inst);
 	mutex_lock(&opts->lock);
 	if (!--midi->free_ref) {
+		cancel_work_sync(&midi->work);
 		kfree(midi->id);
 		kfifo_free(&midi->in_req_fifo);
 		kfree(midi);
author maintainer
#145 lore raw

PATCH 145/744 usb: gadget: printer: fix infinite loop in printer_read()

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Melbin K Mathew <[email protected]>

commit c2e819be6a5c7f34344926b4bd7e3dfca58cf48a upstream.

printer_read() uses the same variable for the requested copy size and the number of bytes actually copied to user space. copy_to_user() returns the number of bytes not copied, so when it fails to copy anything, the computed copied length becomes zero.

In that case len, buf, current_rx_bytes and current_rx_buf are left unchanged. If RX data is available and the user buffer remains unwritable, the read loop can repeat indefinitely.

Track the copied length separately and return -EFAULT, or the number of bytes already copied, if an iteration makes no progress.

Fixes b185f01a9ab7 ("usb: gadget: printer: factor out f_printer")
Cc stable <[email protected]>
---
 drivers/usb/gadget/function/f_printer.c |   23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)
drivers/usb/gadget/function/f_printer.c +18 -5
@@ -431,7 +431,7 @@ printer_read(struct file *fd, char __use
 {
 	struct printer_dev		*dev = fd->private_data;
 	unsigned long			flags;
-	size_t				size;
+	size_t				size, not_copied, copied;
 	size_t				bytes_copied;
 	struct usb_request		*req;
 	/* This is a pointer to the current USB rx request. */
@@ -524,10 +524,12 @@ printer_read(struct file *fd, char __use
 		else
 			size = len;
 
-		size -= copy_to_user(buf, current_rx_buf, size);
-		bytes_copied += size;
-		len -= size;
-		buf += size;
+		not_copied = copy_to_user(buf, current_rx_buf, size);
+		copied = size - not_copied;
+
+		bytes_copied += copied;
+		len -= copied;
+		buf += copied;
 
 		spin_lock_irqsave(&dev->lock, flags);
 
@@ -542,6 +544,17 @@ printer_read(struct file *fd, char __use
 		if (dev->interface < 0)
 			goto out_disabled;
 
+		if (!copied) {
+			dev->current_rx_req = current_rx_req;
+			dev->current_rx_bytes = current_rx_bytes;
+			dev->current_rx_buf = current_rx_buf;
+			spin_unlock_irqrestore(&dev->lock, flags);
+			mutex_unlock(&dev->lock_printer_io);
+			return bytes_copied ? bytes_copied : -EFAULT;
+		}
+
+		size = copied;
+
 		/* If we not returning all the data left in this RX request
 		 * buffer then adjust the amount of data left in the buffer.
 		 * Othewise if we are done with this RX request buffer then
author maintainer
#146 lore raw

PATCH 146/744 USB: gadget: snps-udc: fix device name leak on probe failure

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Johan Hovold <[email protected]>

commit 29a142d3e8b35ebc9e0bcc78f4bc26c9b6a9ac0b upstream.

The gadget device name is set by UDC core when registering the gadget and must not be set before to avoid leaking the name in intermediate error paths (e.g. when detecting an older chip revision).

Fixes 12ad0fcaf2fb ("usb: gadget: amd5536udc: let udc-core manage gadget->dev")
Cc stable <[email protected]>
---
 drivers/usb/gadget/udc/snps_udc_core.c |    1 -
 1 file changed, 1 deletion(-)
drivers/usb/gadget/udc/snps_udc_core.c +0 -1
@@ -3133,7 +3133,6 @@ int udc_probe(struct udc *dev)
 	/* device struct setup */
 	dev->gadget.ops = &udc_ops;
 
-	dev_set_name(&dev->gadget.dev, "gadget");
 	dev->gadget.name = name;
 	dev->gadget.max_speed = USB_SPEED_HIGH;
 
author maintainer
#147 lore raw

PATCH 147/744 USB: gadget: fsl-udc: fix device name leak on probe failure

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Johan Hovold <[email protected]>

commit 6b874d00c466e73c6448a89856407fe46b2f50e4 upstream.

The gadget device name is set by UDC core when registering the gadget and must not be set before to avoid leaking the name in intermediate error paths (e.g. on dma pool creation failure).

Fixes eab35c4e6d95 ("usb: gadget: fsl_udc_core: let udc-core manage gadget->dev")
Cc stable <[email protected]>
---
 drivers/usb/gadget/udc/fsl_udc_core.c |    1 -
 1 file changed, 1 deletion(-)
drivers/usb/gadget/udc/fsl_udc_core.c +0 -1
@@ -2474,7 +2474,6 @@ static int fsl_udc_probe(struct platform
 	udc_controller->gadget.name = driver_name;
 
 	/* Setup gadget.dev and register with kernel */
-	dev_set_name(&udc_controller->gadget.dev, "gadget");
 	udc_controller->gadget.dev.of_node = pdev->dev.of_node;
 
 	if (!IS_ERR_OR_NULL(udc_controller->transceiver))
author maintainer
#148 lore raw

PATCH 148/744 USB: gadget: fsl-udc: fix dev_printk() device

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Johan Hovold <[email protected]>

commit c4dd150fceab281496acb3a643ae712aacb74864 upstream.

A change replacing custom printk() macros with dev_printk() incorrectly used the gadget struct device instead of the controller struct device (including for messages printed before the gadget device name has been initialised).

Switch to using the controller platform device with dev_printk() so that the controller device and driver names are included in log messages as expected.

Fixes 6025f20f16c2 ("usb: gadget: fsl-udc: Replace custom log wrappers by dev_{err,warn,dbg,vdbg}")
Cc stable <[email protected]>
Cc Uwe Kleine-König <[email protected]>
---
 drivers/usb/gadget/udc/fsl_udc_core.c |   92 +++++++++++++++-------------------
 drivers/usb/gadget/udc/fsl_usb2_udc.h |    1 
 2 files changed, 43 insertions(+), 50 deletions(-)
drivers/usb/gadget/udc/fsl_udc_core.c +42 -50
@@ -184,7 +184,7 @@ __acquires(ep->udc->lock)
 	usb_gadget_unmap_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
 
 	if (status && (status != -ESHUTDOWN))
-		dev_vdbg(&udc->gadget.dev, "complete %s req %p stat %d len %u/%u\n",
+		dev_vdbg(udc->dev, "complete %s req %p stat %d len %u/%u\n",
 			 ep->ep.name, &req->req, status,
 			 req->req.actual, req->req.length);
 
@@ -286,7 +286,7 @@ static int dr_controller_setup(struct fs
 	timeout = jiffies + FSL_UDC_RESET_TIMEOUT;
 	while (fsl_readl(&dr_regs->usbcmd) & USB_CMD_CTRL_RESET) {
 		if (time_after(jiffies, timeout)) {
-			dev_err(&udc->gadget.dev, "udc reset timeout!\n");
+			dev_err(udc->dev, "udc reset timeout!\n");
 			return -ETIMEDOUT;
 		}
 		cpu_relax();
@@ -309,7 +309,7 @@ static int dr_controller_setup(struct fs
 	tmp &= USB_EP_LIST_ADDRESS_MASK;
 	fsl_writel(tmp, &dr_regs->endpointlistaddr);
 
-	dev_vdbg(&udc->gadget.dev,
+	dev_vdbg(udc->dev,
 		 "vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x\n",
 		 udc->ep_qh, (int)tmp,
 		 fsl_readl(&dr_regs->endpointlistaddr));
@@ -500,7 +500,7 @@ static void struct_ep_qh_setup(struct fs
 		tmp = max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS;
 		break;
 	default:
-		dev_vdbg(&udc->gadget.dev, "error ep type is %d\n", ep_type);
+		dev_vdbg(udc->dev, "error ep type is %d\n", ep_type);
 		return;
 	}
 	if (zlt)
@@ -613,7 +613,7 @@ static int fsl_ep_enable(struct usb_ep *
 	spin_unlock_irqrestore(&udc->lock, flags);
 	retval = 0;
 
-	dev_vdbg(&udc->gadget.dev, "enabled %s (ep%d%s) maxpacket %d\n",
+	dev_vdbg(udc->dev, "enabled %s (ep%d%s) maxpacket %d\n",
 		 ep->ep.name, ep->ep.desc->bEndpointAddress & 0x0f,
 		 (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
 		 max);
@@ -634,13 +634,8 @@ static int fsl_ep_disable(struct usb_ep
 	int ep_num;
 
 	ep = container_of(_ep, struct fsl_ep, ep);
-	if (!_ep || !ep->ep.desc) {
-		/*
-		 * dev_vdbg(&udc->gadget.dev, "%s not enabled\n",
-		 *	 _ep ? ep->ep.name : NULL);
-		 */
+	if (!_ep || !ep->ep.desc)
 		return -EINVAL;
-	}
 
 	/* disable ep on controller */
 	ep_num = ep_index(ep);
@@ -664,7 +659,7 @@ static int fsl_ep_disable(struct usb_ep
 	ep->stopped = 1;
 	spin_unlock_irqrestore(&udc->lock, flags);
 
-	dev_vdbg(&udc->gadget.dev, "disabled %s OK\n", _ep->name);
+	dev_vdbg(udc->dev, "disabled %s OK\n", _ep->name);
 	return 0;
 }
 
@@ -724,9 +719,6 @@ static void fsl_queue_td(struct fsl_ep *
 {
 	u32 temp, bitmask, tmp_stat;
 
-	/* dev_vdbg(&udc->gadget.dev, "QH addr Register 0x%8x\n", dr_regs->endpointlistaddr);
-	dev_vdbg(&udc->gadget.dev, "ep_qh[%d] addr is 0x%8x\n", i, (u32)&(ep->udc->ep_qh[i])); */
-
 	bitmask = ep_is_in(ep)
 		? (1 << (ep_index(ep) + 16))
 		: (1 << (ep_index(ep)));
@@ -813,7 +805,7 @@ static struct ep_td_struct *fsl_build_dt
 		*is_last = 0;
 
 	if ((*is_last) == 0)
-		dev_vdbg(&udc_controller->gadget.dev, "multi-dtd request!\n");
+		dev_vdbg(udc_controller->dev, "multi-dtd request!\n");
 	/* Fill in the transfer size; set active bit */
 	swap_temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE);
 
@@ -825,7 +817,7 @@ static struct ep_td_struct *fsl_build_dt
 
 	mb();
 
-	dev_vdbg(&udc_controller->gadget.dev, "length = %d address= 0x%x\n", *length, (int)*dma);
+	dev_vdbg(udc_controller->dev, "length = %d address= 0x%x\n", *length, (int)*dma);
 
 	return dtd;
 }
@@ -876,11 +868,11 @@ fsl_ep_queue(struct usb_ep *_ep, struct
 	/* catch various bogus parameters */
 	if (!_req || !req->req.complete || !req->req.buf
 			|| !list_empty(&req->queue)) {
-		dev_vdbg(&udc->gadget.dev, "%s, bad params\n", __func__);
+		dev_vdbg(udc->dev, "%s, bad params\n", __func__);
 		return -EINVAL;
 	}
 	if (unlikely(!ep->ep.desc)) {
-		dev_vdbg(&udc->gadget.dev, "%s, bad ep\n", __func__);
+		dev_vdbg(udc->dev, "%s, bad ep\n", __func__);
 		return -EINVAL;
 	}
 	if (usb_endpoint_xfer_isoc(ep->ep.desc)) {
@@ -1040,7 +1032,7 @@ static int fsl_ep_set_halt(struct usb_ep
 		udc->ep0_dir = 0;
 	}
 out:
-	dev_vdbg(&udc->gadget.dev, "%s %s halt stat %d\n", ep->ep.name,
+	dev_vdbg(udc->dev, "%s %s halt stat %d\n", ep->ep.name,
 		 value ?  "set" : "clear", status);
 
 	return status;
@@ -1109,7 +1101,7 @@ static void fsl_ep_fifo_flush(struct usb
 		/* Wait until flush complete */
 		while (fsl_readl(&dr_regs->endptflush)) {
 			if (time_after(jiffies, timeout)) {
-				dev_err(&udc_controller->gadget.dev,
+				dev_err(udc_controller->dev,
 					"ep flush timeout\n");
 				return;
 			}
@@ -1182,7 +1174,7 @@ static int fsl_vbus_session(struct usb_g
 
 	udc = container_of(gadget, struct fsl_udc, gadget);
 	spin_lock_irqsave(&udc->lock, flags);
-	dev_vdbg(&gadget->dev, "VBUS %s\n", str_on_off(is_active));
+	dev_vdbg(udc->dev, "VBUS %s\n", str_on_off(is_active));
 	udc->vbus_active = (is_active != 0);
 	if (can_pullup(udc))
 		fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
@@ -1548,7 +1540,7 @@ static void ep0_req_complete(struct fsl_
 		udc->ep0_state = WAIT_FOR_SETUP;
 		break;
 	case WAIT_FOR_SETUP:
-		dev_err(&udc->gadget.dev, "Unexpected ep0 packets\n");
+		dev_err(udc->dev, "Unexpected ep0 packets\n");
 		break;
 	default:
 		ep0stall(udc);
@@ -1617,7 +1609,7 @@ static int process_ep_req(struct fsl_udc
 		errors = hc32_to_cpu(curr_td->size_ioc_sts);
 		if (errors & DTD_ERROR_MASK) {
 			if (errors & DTD_STATUS_HALTED) {
-				dev_err(&udc->gadget.dev, "dTD error %08x QH=%d\n", errors, pipe);
+				dev_err(udc->dev, "dTD error %08x QH=%d\n", errors, pipe);
 				/* Clear the errors and Halt condition */
 				tmp = hc32_to_cpu(curr_qh->size_ioc_int_sts);
 				tmp &= ~errors;
@@ -1628,26 +1620,26 @@ static int process_ep_req(struct fsl_udc
 				break;
 			}
 			if (errors & DTD_STATUS_DATA_BUFF_ERR) {
-				dev_vdbg(&udc->gadget.dev, "Transfer overflow\n");
+				dev_vdbg(udc->dev, "Transfer overflow\n");
 				status = -EPROTO;
 				break;
 			} else if (errors & DTD_STATUS_TRANSACTION_ERR) {
-				dev_vdbg(&udc->gadget.dev, "ISO error\n");
+				dev_vdbg(udc->dev, "ISO error\n");
 				status = -EILSEQ;
 				break;
 			} else
-				dev_err(&udc->gadget.dev,
+				dev_err(udc->dev,
 					"Unknown error has occurred (0x%x)!\n",
 					errors);
 
 		} else if (hc32_to_cpu(curr_td->size_ioc_sts)
 				& DTD_STATUS_ACTIVE) {
-			dev_vdbg(&udc->gadget.dev, "Request not complete\n");
+			dev_vdbg(udc->dev, "Request not complete\n");
 			status = REQ_UNCOMPLETE;
 			return status;
 		} else if (remaining_length) {
 			if (direction) {
-				dev_vdbg(&udc->gadget.dev,
+				dev_vdbg(udc->dev,
 					 "Transmit dTD remaining length not zero\n");
 				status = -EPROTO;
 				break;
@@ -1655,8 +1647,7 @@ static int process_ep_req(struct fsl_udc
 				break;
 			}
 		} else {
-			dev_vdbg(&udc->gadget.dev,
-				 "dTD transmitted successful\n");
+			dev_vdbg(udc->dev, "dTD transmitted successful\n");
 		}
 
 		if (j != curr_req->dtd_count - 1)
@@ -1699,7 +1690,7 @@ static void dtd_complete_irq(struct fsl_
 
 		/* If the ep is configured */
 		if (!curr_ep->ep.name) {
-			dev_warn(&udc->gadget.dev, "Invalid EP?\n");
+			dev_warn(udc->dev, "Invalid EP?\n");
 			continue;
 		}
 
@@ -1708,7 +1699,7 @@ static void dtd_complete_irq(struct fsl_
 				queue) {
 			status = process_ep_req(udc, i, curr_req);
 
-			dev_vdbg(&udc->gadget.dev,
+			dev_vdbg(udc->dev,
 				 "status of process_ep_req= %d, ep = %d\n",
 				 status, ep_num);
 			if (status == REQ_UNCOMPLETE)
@@ -1829,7 +1820,7 @@ static void reset_irq(struct fsl_udc *ud
 	while (fsl_readl(&dr_regs->endpointprime)) {
 		/* Wait until all endptprime bits cleared */
 		if (time_after(jiffies, timeout)) {
-			dev_err(&udc->gadget.dev, "Timeout for reset\n");
+			dev_err(udc->dev, "Timeout for reset\n");
 			break;
 		}
 		cpu_relax();
@@ -1839,7 +1830,7 @@ static void reset_irq(struct fsl_udc *ud
 	fsl_writel(0xffffffff, &dr_regs->endptflush);
 
 	if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) {
-		dev_vdbg(&udc->gadget.dev, "Bus reset\n");
+		dev_vdbg(udc->dev, "Bus reset\n");
 		/* Bus is reseting */
 		udc->bus_reset = 1;
 		/* Reset all the queues, include XD, dTD, EP queue
@@ -1847,7 +1838,7 @@ static void reset_irq(struct fsl_udc *ud
 		reset_queues(udc, true);
 		udc->usb_state = USB_STATE_DEFAULT;
 	} else {
-		dev_vdbg(&udc->gadget.dev, "Controller reset\n");
+		dev_vdbg(udc->dev, "Controller reset\n");
 		/* initialize usb hw reg except for regs for EP, not
 		 * touch usbintr reg */
 		dr_controller_setup(udc);
@@ -1881,7 +1872,7 @@ static irqreturn_t fsl_udc_irq(int irq,
 	/* Clear notification bits */
 	fsl_writel(irq_src, &dr_regs->usbsts);
 
-	/* dev_vdbg(&udc->gadget.dev, "irq_src [0x%8x]", irq_src); */
+	/* dev_vdbg(udc->dev, "irq_src [0x%8x]", irq_src); */
 
 	/* Need to resume? */
 	if (udc->usb_state == USB_STATE_SUSPENDED)
@@ -1890,7 +1881,7 @@ static irqreturn_t fsl_udc_irq(int irq,
 
 	/* USB Interrupt */
 	if (irq_src & USB_STS_INT) {
-		dev_vdbg(&udc->gadget.dev, "Packet int\n");
+		dev_vdbg(udc->dev, "Packet int\n");
 		/* Setup package, we only support ep0 as control ep */
 		if (fsl_readl(&dr_regs->endptsetupstat) & EP_SETUP_STATUS_EP0) {
 			tripwire_handler(udc, 0,
@@ -1919,7 +1910,7 @@ static irqreturn_t fsl_udc_irq(int irq,
 
 	/* Reset Received */
 	if (irq_src & USB_STS_RESET) {
-		dev_vdbg(&udc->gadget.dev, "reset int\n");
+		dev_vdbg(udc->dev, "reset int\n");
 		reset_irq(udc);
 		status = IRQ_HANDLED;
 	}
@@ -1931,7 +1922,7 @@ static irqreturn_t fsl_udc_irq(int irq,
 	}
 
 	if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) {
-		dev_vdbg(&udc->gadget.dev, "Error IRQ %x\n", irq_src);
+		dev_vdbg(udc->dev, "Error IRQ %x\n", irq_src);
 	}
 
 	spin_unlock_irqrestore(&udc->lock, flags);
@@ -1967,7 +1958,7 @@ static int fsl_udc_start(struct usb_gadg
 					udc_controller->transceiver->otg,
 						    &udc_controller->gadget);
 			if (retval < 0) {
-				dev_err(&udc_controller->gadget.dev, "can't bind to transceiver\n");
+				dev_err(udc_controller->dev, "can't bind to transceiver\n");
 				udc_controller->driver = NULL;
 				return retval;
 			}
@@ -2252,7 +2243,7 @@ static int struct_udc_setup(struct fsl_u
 
 	udc->eps = kzalloc_objs(struct fsl_ep, udc->max_ep);
 	if (!udc->eps) {
-		dev_err(&udc->gadget.dev, "kmalloc udc endpoint status failed\n");
+		dev_err(udc->dev, "kmalloc udc endpoint status failed\n");
 		goto eps_alloc_failed;
 	}
 
@@ -2267,7 +2258,7 @@ static int struct_udc_setup(struct fsl_u
 	udc->ep_qh = dma_alloc_coherent(&pdev->dev, size,
 					&udc->ep_qh_dma, GFP_KERNEL);
 	if (!udc->ep_qh) {
-		dev_err(&udc->gadget.dev, "malloc QHs for udc failed\n");
+		dev_err(udc->dev, "malloc QHs for udc failed\n");
 		goto ep_queue_alloc_failed;
 	}
 
@@ -2278,14 +2269,14 @@ static int struct_udc_setup(struct fsl_u
 	udc->status_req = container_of(fsl_alloc_request(NULL, GFP_KERNEL),
 			struct fsl_req, req);
 	if (!udc->status_req) {
-		dev_err(&udc->gadget.dev, "kzalloc for udc status request failed\n");
+		dev_err(udc->dev, "kzalloc for udc status request failed\n");
 		goto udc_status_alloc_failed;
 	}
 
 	/* allocate a small amount of memory to get valid address */
 	udc->status_req->req.buf = kmalloc(8, GFP_KERNEL);
 	if (!udc->status_req->req.buf) {
-		dev_err(&udc->gadget.dev, "kzalloc for udc request buffer failed\n");
+		dev_err(udc->dev, "kzalloc for udc request buffer failed\n");
 		goto udc_req_buf_alloc_failed;
 	}
 
@@ -2373,6 +2364,7 @@ static int fsl_udc_probe(struct platform
 	if (udc_controller == NULL)
 		return -ENOMEM;
 
+	udc_controller->dev = &pdev->dev;
 	pdata = dev_get_platdata(&pdev->dev);
 	udc_controller->pdata = pdata;
 	spin_lock_init(&udc_controller->lock);
@@ -2382,7 +2374,7 @@ static int fsl_udc_probe(struct platform
 	if (pdata->operating_mode == FSL_USB2_DR_OTG) {
 		udc_controller->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
 		if (IS_ERR_OR_NULL(udc_controller->transceiver)) {
-			dev_err(&udc_controller->gadget.dev, "Can't find OTG driver!\n");
+			dev_err(&pdev->dev, "Can't find OTG driver!\n");
 			ret = -ENODEV;
 			goto err_kfree;
 		}
@@ -2398,7 +2390,7 @@ static int fsl_udc_probe(struct platform
 	if (pdata->operating_mode == FSL_USB2_DR_DEVICE) {
 		if (!request_mem_region(res->start, resource_size(res),
 					driver_name)) {
-			dev_err(&udc_controller->gadget.dev, "request mem region for %s failed\n", pdev->name);
+			dev_err(&pdev->dev, "failed to request mem region\n");
 			ret = -EBUSY;
 			goto err_kfree;
 		}
@@ -2429,7 +2421,7 @@ static int fsl_udc_probe(struct platform
 	/* Read Device Controller Capability Parameters register */
 	dccparams = fsl_readl(&dr_regs->dccparams);
 	if (!(dccparams & DCCPARAMS_DC)) {
-		dev_err(&udc_controller->gadget.dev, "This SOC doesn't support device role\n");
+		dev_err(&pdev->dev, "This SOC doesn't support device role\n");
 		ret = -ENODEV;
 		goto err_exit;
 	}
@@ -2447,14 +2439,14 @@ static int fsl_udc_probe(struct platform
 	ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED,
 			driver_name, udc_controller);
 	if (ret != 0) {
-		dev_err(&udc_controller->gadget.dev, "cannot request irq %d err %d\n",
+		dev_err(&pdev->dev, "cannot request irq %d err %d\n",
 				udc_controller->irq, ret);
 		goto err_exit;
 	}
 
 	/* Initialize the udc structure including QH member and other member */
 	if (struct_udc_setup(udc_controller, pdev)) {
-		dev_err(&udc_controller->gadget.dev, "Can't initialize udc data structure\n");
+		dev_err(&pdev->dev, "Can't initialize udc data structure\n");
 		ret = -ENOMEM;
 		goto err_free_irq;
 	}
drivers/usb/gadget/udc/fsl_usb2_udc.h +1 -0
@@ -470,6 +470,7 @@ struct fsl_ep {
 #define EP_DIR_OUT	0
 
 struct fsl_udc {
+	struct device *dev;
 	struct usb_gadget gadget;
 	struct usb_gadget_driver *driver;
 	struct fsl_usb2_platform_data *pdata;
author maintainer
#149 lore raw

PATCH 149/744 usb: gadget: f_ncm: validate datagram bounds in ncm_unwrap_ntb()

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sonali Pradhan <[email protected]>

commit 1febec7e47cdcd01f43fb0211094e3010474666e upstream.

When unpacking host-supplied NTBs, ncm_unwrap_ntb() checks datagram length against frame_max but does not verify that the datagram fits within the declared block length. Additionally, when decoding multiple NTBs from a single socket buffer, subsequent block lengths are not checked against the actual remaining buffer data.

With these checks missing, a malicious USB host can specify datagram offsets and lengths that point beyond the block, or supply secondary NTB headers declaring lengths larger than the buffer. skb_put_data() then copies adjacent kernel memory from skb_shared_info into the network skb.

Fix this by verifying that sufficient buffer space remains for the NTB header before parsing, handling zero-length block declarations, ensuring that block lengths never exceed the remaining buffer space, and verifying that each datagram payload stays strictly within the block boundary.

Fixes 427694cfaafa ("usb: gadget: ncm: Handle decoding of multiple NTB's in unwrap call")
Fixes 2b74b0a04d3e ("USB: gadget: f_ncm: add bounds checks to ncm_unwrap_ntb()")
Cc stable <[email protected]>
Assisted-by Jetski:Gemini-2.5-Pro
---
 drivers/usb/gadget/function/f_ncm.c |   17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)
drivers/usb/gadget/function/f_ncm.c +13 -4
@@ -1189,6 +1189,10 @@ static int ncm_unwrap_ntb(struct gether
 	frame_max = ncm_opts->max_segment_size;
 
 parse_ntb:
+	if (to_process < (int)opts->nth_size) {
+		INFO(port->func.config->cdev, "Packet too small for headers\n");
+		goto err;
+	}
 	tmp = (__le16 *)ntb_ptr;
 
 	/* dwSignature */
@@ -1209,8 +1213,12 @@ parse_ntb:
 	tmp++; /* skip wSequence */
 
 	block_len = get_ncm(&tmp, opts->block_length);
+	if (block_len == 0)
+		block_len = to_process;
+
 	/* (d)wBlockLength */
-	if ((block_len < opts->nth_size + opts->ndp_size) || (block_len > ntb_max)) {
+	if ((block_len < opts->nth_size + opts->ndp_size) || (block_len > ntb_max) ||
+			(block_len > to_process)) {
 		INFO(port->func.config->cdev, "Bad block length: %#X\n", block_len);
 		goto err;
 	}
@@ -1273,7 +1281,7 @@ parse_ntb:
 			index = index2;
 			/* wDatagramIndex[0] */
 			if ((index < opts->nth_size) ||
-					(index > block_len - opts->dpe_size)) {
+					(index > block_len)) {
 				INFO(port->func.config->cdev,
 				     "Bad index: %#X\n", index);
 				goto err;
@@ -1285,7 +1293,8 @@ parse_ntb:
 			 * ethernet hdr + crc or larger than max frame size
 			 */
 			if ((dg_len < 14 + crc_len) ||
-					(dg_len > frame_max)) {
+					(dg_len > frame_max) ||
+					(dg_len > block_len - index)) {
 				INFO(port->func.config->cdev,
 				     "Bad dgram length: %#X\n", dg_len);
 				goto err;
@@ -1310,7 +1319,7 @@ parse_ntb:
 			dg_len2 = get_ncm(&tmp, opts->dgram_item_len);
 
 			/* wDatagramIndex[1] */
-			if (index2 > block_len - opts->dpe_size) {
+			if (index2 > block_len) {
 				INFO(port->func.config->cdev,
 				     "Bad index: %#X\n", index2);
 				goto err;
author maintainer
#150 lore raw

PATCH 150/744 usb: gadget: f_tcm: synchronize delayed set_alt with teardown

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Cen Zhang <[email protected]>

commit 79e2d75725c85607f8a9d87ae9cace62a19f767d upstream.

The f_tcm set_alt() path defers endpoint setup to a work item and completes the delayed status response from process context. The delayed work uses f_tcm private state and may complete the setup request after disconnect or function teardown has already moved on.

Cancel and drain the delayed set_alt work when the function is unbound or freed. For disable paths, which are reached under the composite device lock, use a small state machine and a non-sleeping cancellation path instead of cancel_work_sync(). If the work is already running, mark it cancelled and let the worker own the cleanup; otherwise tcm_disable() can cancel the queued work and clean up immediately.

Also serialize the final delayed-status completion with the cancellation check while holding the composite device lock. This prevents a disconnect from clearing delayed_status while the worker is about to complete the control request.

Validation reproduced this kernel report:

BUG: KASAN: slab-use-after-free in tcm_delayed_set_alt+0x6c/0xef0

Call Trace:
 <TASK>
 dump_stack_lvl+0x66/0xa0
 print_report+0xce/0x630
 ? tcm_delayed_set_alt+0x6c/0xef0
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? __virt_addr_valid+0x188/0x320
 ? tcm_delayed_set_alt+0x6c/0xef0
 kasan_report+0xe0/0x110
 ? tcm_delayed_set_alt+0x6c/0xef0
 tcm_delayed_set_alt+0x6c/0xef0
 ? __pfx_tcm_delayed_set_alt+0x10/0x10
 ? process_one_work+0x4cb/0xb90
 ? rcu_is_watching+0x20/0x50
 ? tcm_delayed_set_alt+0x9/0xef0
 process_one_work+0x4d7/0xb90
 ? __pfx_process_one_work+0x10/0x10
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? __list_add_valid_or_report+0x37/0xf0
 ? __pfx_tcm_delayed_set_alt+0x10/0x10
 ? srso_alias_return_thunk+0x5/0xfbef5
 worker_thread+0x2d8/0x570
 ? __pfx_worker_thread+0x10/0x10
 kthread+0x1ad/0x1f0
 ? __pfx_kthread+0x10/0x10
 ret_from_fork+0x3c9/0x540
 ? __pfx_ret_from_fork+0x10/0x10
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? __switch_to+0x2e9/0x730
 ? __pfx_kthread+0x10/0x10
 ret_from_fork_asm+0x1a/0x30
 </TASK>

Allocated by task 544:
 kasan_save_stack+0x33/0x60
 kasan_save_track+0x14/0x30
 __kasan_kmalloc+0x8f/0xa0
 tcm_alloc+0x68/0x180
 usb_get_function+0x36/0x60
 config_usb_cfg_link+0x125/0x1b0
 configfs_symlink+0x322/0x890
 vfs_symlink+0xc2/0x270
 filename_symlinkat+0x295/0x2f0
 __x64_sys_symlinkat+0x62/0x90
 do_syscall_64+0x115/0x6a0
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 661:
 kasan_save_stack+0x33/0x60
 kasan_save_track+0x14/0x30
 kasan_save_free_info+0x3b/0x60
 __kasan_slab_free+0x43/0x70
 kfree+0x2f9/0x530
 config_usb_cfg_unlink+0x173/0x1e0
 configfs_unlink+0x1fa/0x340
 vfs_unlink+0x15c/0x510
 filename_unlinkat+0x2ba/0x450
 __x64_sys_unlinkat+0x63/0x90
 do_syscall_64+0x115/0x6a0
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
Fixes c52661d60f63 ("usb-gadget: Initial merge of target module for UASP + BOT")
Cc stable <[email protected]>
Assisted-by Codex:gpt-5.5
---
 drivers/usb/gadget/function/f_tcm.c |  192 ++++++++++++++++++++++++++++++------
 drivers/usb/gadget/function/tcm.h   |   13 ++
 2 files changed, 177 insertions(+), 28 deletions(-)
drivers/usb/gadget/function/f_tcm.c +164 -28
@@ -2363,31 +2363,158 @@ ep_fail:
 	return -ENOTSUPP;
 }
 
-struct guas_setup_wq {
-	struct work_struct work;
-	struct f_uas *fu;
-	unsigned int alt;
-};
+static void tcm_cleanup_old_alt(struct f_uas *fu)
+{
+	if (fu->flags & USBG_IS_UAS)
+		uasp_cleanup_old_alt(fu);
+	else if (fu->flags & USBG_IS_BOT)
+		bot_cleanup_old_alt(fu);
+	fu->flags = 0;
+}
+
+static void tcm_delayed_set_alt_done(struct f_uas *fu)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
+	fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_IDLE;
+	fu->delayed_set_alt_cancel = false;
+	spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
+}
+
+static bool tcm_delayed_set_alt_cancelled(struct f_uas *fu)
+{
+	bool cancelled;
+	unsigned long flags;
+
+	spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
+	cancelled = fu->delayed_set_alt_cancel;
+	spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
+
+	return cancelled;
+}
+
+static bool tcm_complete_delayed_status(struct f_uas *fu)
+{
+	struct usb_composite_dev *cdev = fu->function.config->cdev;
+	struct usb_request *req = cdev->req;
+	unsigned long cdev_flags;
+	bool cancelled;
+	int ret;
+
+	spin_lock_irqsave(&cdev->lock, cdev_flags);
+	spin_lock(&fu->delayed_set_alt_lock);
+	cancelled = fu->delayed_set_alt_cancel;
+	if (!cancelled) {
+		fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_IDLE;
+		fu->delayed_set_alt_cancel = false;
+	}
+	spin_unlock(&fu->delayed_set_alt_lock);
+
+	if (cancelled) {
+		spin_unlock_irqrestore(&cdev->lock, cdev_flags);
+		return false;
+	}
+
+	if (cdev->delayed_status == 0) {
+		WARN(cdev, "%s: Unexpected call\n", __func__);
+	} else if (--cdev->delayed_status == 0) {
+		req->length = 0;
+		req->context = cdev;
+		ret = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+		if (ret == 0) {
+			cdev->setup_pending = true;
+		} else {
+			req->status = 0;
+			req->complete(cdev->gadget->ep0, req);
+		}
+	}
+
+	spin_unlock_irqrestore(&cdev->lock, cdev_flags);
+
+	return true;
+}
+
+static bool tcm_cancel_delayed_set_alt(struct f_uas *fu)
+{
+	bool cleanup = false;
+	bool cancel = false;
+	unsigned long flags;
+
+	spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
+	switch (fu->delayed_set_alt_state) {
+	case USBG_DELAYED_SET_ALT_IDLE:
+		cleanup = true;
+		break;
+	case USBG_DELAYED_SET_ALT_QUEUED:
+	case USBG_DELAYED_SET_ALT_RUNNING:
+		fu->delayed_set_alt_cancel = true;
+		cancel = true;
+		break;
+	}
+	spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
+
+	if (cancel && cancel_work(&fu->delayed_set_alt)) {
+		spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
+		if (fu->delayed_set_alt_state == USBG_DELAYED_SET_ALT_QUEUED) {
+			fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_IDLE;
+			fu->delayed_set_alt_cancel = false;
+			cleanup = true;
+		}
+		spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
+	}
+
+	return cleanup;
+}
+
+static void tcm_cancel_delayed_set_alt_sync(struct f_uas *fu)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
+	if (fu->delayed_set_alt_state != USBG_DELAYED_SET_ALT_IDLE)
+		fu->delayed_set_alt_cancel = true;
+	spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
+
+	cancel_work_sync(&fu->delayed_set_alt);
+
+	spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
+	fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_IDLE;
+	fu->delayed_set_alt_cancel = false;
+	spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
+}
 
 static void tcm_delayed_set_alt(struct work_struct *wq)
 {
-	struct guas_setup_wq *work = container_of(wq, struct guas_setup_wq,
-			work);
-	struct f_uas *fu = work->fu;
-	int alt = work->alt;
+	struct f_uas *fu = container_of(wq, struct f_uas, delayed_set_alt);
+	unsigned long flags;
+	unsigned int alt;
+
+	spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
+	if (fu->delayed_set_alt_state != USBG_DELAYED_SET_ALT_QUEUED) {
+		spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
+		return;
+	}
+	fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_RUNNING;
+	alt = fu->delayed_alt;
+	spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
 
-	kfree(work);
+	tcm_cleanup_old_alt(fu);
 
-	if (fu->flags & USBG_IS_BOT)
-		bot_cleanup_old_alt(fu);
-	if (fu->flags & USBG_IS_UAS)
-		uasp_cleanup_old_alt(fu);
+	if (tcm_delayed_set_alt_cancelled(fu))
+		goto out_done;
 
 	if (alt == USB_G_ALT_INT_BBB)
 		bot_set_alt(fu);
 	else if (alt == USB_G_ALT_INT_UAS)
 		uasp_set_alt(fu);
-	usb_composite_setup_continue(fu->function.config->cdev);
+
+	if (tcm_complete_delayed_status(fu))
+		return;
+
+	tcm_cleanup_old_alt(fu);
+out_done:
+	tcm_delayed_set_alt_done(fu);
 }
 
 static int tcm_get_alt(struct usb_function *f, unsigned intf)
@@ -2413,15 +2540,20 @@ static int tcm_set_alt(struct usb_functi
 		return -EOPNOTSUPP;
 
 	if ((alt == USB_G_ALT_INT_BBB) || (alt == USB_G_ALT_INT_UAS)) {
-		struct guas_setup_wq *work;
+		unsigned long flags;
+
+		spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
+		if (fu->delayed_set_alt_state != USBG_DELAYED_SET_ALT_IDLE) {
+			spin_unlock_irqrestore(&fu->delayed_set_alt_lock,
+					       flags);
+			return -EBUSY;
+		}
+		fu->delayed_alt = alt;
+		fu->delayed_set_alt_cancel = false;
+		fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_QUEUED;
+		spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
 
-		work = kmalloc_obj(*work, GFP_ATOMIC);
-		if (!work)
-			return -ENOMEM;
-		INIT_WORK(&work->work, tcm_delayed_set_alt);
-		work->fu = fu;
-		work->alt = alt;
-		schedule_work(&work->work);
+		schedule_work(&fu->delayed_set_alt);
 		return USB_GADGET_DELAYED_STATUS;
 	}
 	return -EOPNOTSUPP;
@@ -2431,11 +2563,8 @@ static void tcm_disable(struct usb_funct
 {
 	struct f_uas *fu = to_f_uas(f);
 
-	if (fu->flags & USBG_IS_UAS)
-		uasp_cleanup_old_alt(fu);
-	else if (fu->flags & USBG_IS_BOT)
-		bot_cleanup_old_alt(fu);
-	fu->flags = 0;
+	if (tcm_cancel_delayed_set_alt(fu))
+		tcm_cleanup_old_alt(fu);
 }
 
 static int tcm_setup(struct usb_function *f,
@@ -2583,11 +2712,16 @@ static void tcm_free(struct usb_function
 {
 	struct f_uas *tcm = to_f_uas(f);
 
+	tcm_cancel_delayed_set_alt_sync(tcm);
 	kfree(tcm);
 }
 
 static void tcm_unbind(struct usb_configuration *c, struct usb_function *f)
 {
+	struct f_uas *fu = to_f_uas(f);
+
+	tcm_cancel_delayed_set_alt_sync(fu);
+	tcm_cleanup_old_alt(fu);
 	usb_free_all_descriptors(f);
 }
 
@@ -2620,6 +2754,8 @@ static struct usb_function *tcm_alloc(st
 	fu->function.disable = tcm_disable;
 	fu->function.free_func = tcm_free;
 	fu->tpg = tpg_instances[i].tpg;
+	INIT_WORK(&fu->delayed_set_alt, tcm_delayed_set_alt);
+	spin_lock_init(&fu->delayed_set_alt_lock);
 
 	hash_init(fu->stream_hash);
 	mutex_unlock(&tpg_instances_lock);
drivers/usb/gadget/function/tcm.h +13 -0
@@ -3,6 +3,7 @@
 #define __TARGET_USB_GADGET_H__
 
 #include <linux/kref.h>
+#include <linux/spinlock.h>
 /* #include <linux/usb/uas.h> */
 #include <linux/hashtable.h>
 #include <linux/usb/composite.h>
@@ -29,6 +30,12 @@ enum {
 
 #define USB_G_DEFAULT_SESSION_TAGS	USBG_NUM_CMDS
 
+enum {
+	USBG_DELAYED_SET_ALT_IDLE = 0,
+	USBG_DELAYED_SET_ALT_QUEUED,
+	USBG_DELAYED_SET_ALT_RUNNING,
+};
+
 struct tcm_usbg_nexus {
 	struct se_session *tvn_se_sess;
 };
@@ -132,6 +139,12 @@ struct f_uas {
 #define USBG_BOT_CMD_PEND	(1 << 4)
 #define USBG_BOT_WEDGED		(1 << 5)
 
+	struct work_struct	delayed_set_alt;
+	spinlock_t		delayed_set_alt_lock; /* protects delayed_set_alt_* */
+	unsigned int		delayed_alt;
+	unsigned int		delayed_set_alt_state;
+	bool			delayed_set_alt_cancel;
+
 	struct usbg_cdb		cmd[USBG_NUM_CMDS];
 	struct usb_ep		*ep_in;
 	struct usb_ep		*ep_out;
author maintainer
#151 lore raw

PATCH 151/744 usb: gadget: udc: bdc: free IRQ and drain func_wake_notify before teardown

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Fan Wu <[email protected]>

commit 0583f2fbf8f86ae3a0ce054f96783dd83e65d9bb upstream.

The Broadcom BDC UDC driver registers its IRQ handler with devm_request_irq() in bdc_udc_init(), so the IRQ is released by devm only after bdc_remove() returns. devm releases resources in reverse LIFO order, but bdc_remove() runs bdc_udc_exit() and bdc_hw_exit() -> bdc_mem_free() manually before returning: bdc_udc_exit() tears down individual endpoint objects via bdc_free_ep(), while bdc_hw_exit() -> bdc_mem_free() frees and NULLs the DMA-coherent status-report ring (bdc->srr.sr_bds) and kfree()s bdc->bdc_ep_array. Both happen while the IRQ handler (bdc_udc_interrupt, requested with IRQF_SHARED) remains deliverable in the window up to the post-remove devm free_irq().

On receipt of a shared interrupt in that window, bdc_udc_interrupt() dereferences bdc->srr.sr_bds[bdc->srr.dqp_index] (NULL or freed DMA) and dispatches sr_handler callbacks that index into bdc_ep_array, causing a NULL-deref or use-after-free.

The same window affects the delayed_work bdc->func_wake_notify, which is armed from the IRQ handler via bdc_sr_uspc() -> handle_link_state_change() -> schedule_delayed_work() and may self-rearm from its own callback bdc_func_wake_timer(). No cancel exists anywhere in the driver, so a queued work item that fires after bdc_remove() returns and the bdc structure is devm-freed dereferences freed memory.

Replace devm_request_irq() with request_irq() and add an explicit free_irq(bdc->irq, bdc) in bdc_remove(). Clear BDC_GIE before free_irq() to stop the device from asserting interrupts, then free_irq() drains any in-flight handler, then cancel_delayed_work_sync() drains the func_wake_notify delayed work. This ordering ensures the IRQ handler and delayed work cannot interfere with the subsequent endpoint and DMA teardown in bdc_udc_exit() and bdc_hw_exit(). Wire the matching free_irq() into the bdc_udc_init() error path so the IRQ is released on probe failure, and route the bdc_init_ep() failure through err0 instead of returning directly.

This issue was found by an in-house static analysis tool.

Fixes efed421a94e6 ("usb: gadget: Add UDC driver for Broadcom USB3.0 device controller IP BDC")
Cc stable <[email protected]>
Assisted-by Codex:gpt-5.5
---
 drivers/usb/gadget/udc/bdc/bdc_core.c |   20 ++++++++++++++++++++
 drivers/usb/gadget/udc/bdc/bdc_udc.c  |    7 ++++---
 2 files changed, 24 insertions(+), 3 deletions(-)
drivers/usb/gadget/udc/bdc/bdc_core.c +20 -0
@@ -585,9 +585,29 @@ disable_clk:
 static void bdc_remove(struct platform_device *pdev)
 {
 	struct bdc *bdc;
+	unsigned long flags;
+	u32 temp;
 
 	bdc  = platform_get_drvdata(pdev);
 	dev_dbg(bdc->dev, "%s ()\n", __func__);
+	/*
+	 * Disable the device interrupt source before freeing the IRQ:
+	 * clear BDC_GIE so the controller stops asserting interrupts,
+	 * then free_irq drains any in-flight handler.
+	 */
+	spin_lock_irqsave(&bdc->lock, flags);
+	temp = bdc_readl(bdc->regs, BDC_BDCSC);
+	temp &= ~BDC_GIE;
+	bdc_writel(bdc->regs, BDC_BDCSC, temp);
+	spin_unlock_irqrestore(&bdc->lock, flags);
+	free_irq(bdc->irq, bdc);
+	/*
+	 * Drain func_wake_notify after free_irq: the IRQ handler arms this
+	 * delayed_work via bdc_sr_uspc -> handle_link_state_change ->
+	 * schedule_delayed_work (self-rearmed in bdc_func_wake_timer), so
+	 * the IRQ must be released first to prevent re-arm after cancel.
+	 */
+	cancel_delayed_work_sync(&bdc->func_wake_notify);
 	bdc_udc_exit(bdc);
 	bdc_hw_exit(bdc);
 	bdc_phy_exit(bdc);
drivers/usb/gadget/udc/bdc/bdc_udc.c +4 -3
@@ -530,8 +530,8 @@ int bdc_udc_init(struct bdc *bdc)
 
 
 	bdc->gadget.name = BRCM_BDC_NAME;
-	ret = devm_request_irq(bdc->dev, bdc->irq, bdc_udc_interrupt,
-				IRQF_SHARED, BRCM_BDC_NAME, bdc);
+	ret = request_irq(bdc->irq, bdc_udc_interrupt, IRQF_SHARED,
+			  BRCM_BDC_NAME, bdc);
 	if (ret) {
 		dev_err(bdc->dev,
 			"failed to request irq #%d %d\n",
@@ -542,7 +542,7 @@ int bdc_udc_init(struct bdc *bdc)
 	ret = bdc_init_ep(bdc);
 	if (ret) {
 		dev_err(bdc->dev, "bdc init ep fail: %d\n", ret);
-		return ret;
+		goto err0;
 	}
 
 	ret = usb_add_gadget_udc(bdc->dev, &bdc->gadget);
@@ -571,6 +571,7 @@ int bdc_udc_init(struct bdc *bdc)
 err1:
 	usb_del_gadget_udc(&bdc->gadget);
 err0:
+	free_irq(bdc->irq, bdc);
 	bdc_free_ep(bdc);
 
 	return ret;
author maintainer
#152 lore raw

PATCH 152/744 usb: gadget: uvc: clamp SEND_RESPONSE length to the response buffer

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Muhammad Bilal <[email protected]>

commit b70dc75e85ba968b7b76eebfe5d63000080b875b upstream.

uvc_send_response() builds the UVC control response from a user-supplied struct uvc_request_data:

	req->length = min_t(unsigned int, uvc->event_length, data->length);
	...
	memcpy(req->buf, data->data, req->length);

req->length is clamped to uvc->event_length, which is taken from the host control request wLength (up to UVC_MAX_REQUEST_SIZE, 64), and to data->length, which comes from the UVCIOC_SEND_RESPONSE ioctl and is only checked for being negative. The source buffer data->data is only 60 bytes, so a response with uvc->event_length and data->length both greater than 60 makes memcpy() read past the end of data->data.

Clamp req->length to sizeof(data->data) as well.

Fixes a5eaaa1f33e7 ("usb: gadget: uvc: use capped length value")
Cc stable <[email protected]>
---
 drivers/usb/gadget/function/uvc_v4l2.c |    2 ++
 1 file changed, 2 insertions(+)
drivers/usb/gadget/function/uvc_v4l2.c +2 -0
@@ -200,6 +200,8 @@ uvc_send_response(struct uvc_device *uvc
 		return usb_ep_set_halt(cdev->gadget->ep0);
 
 	req->length = min_t(unsigned int, uvc->event_length, data->length);
+	if (req->length > sizeof(data->data))
+		req->length = sizeof(data->data);
 	req->zero = data->length < uvc->event_length;
 
 	memcpy(req->buf, data->data, req->length);
author maintainer
#153 lore raw

PATCH 153/744 USB: serial: ftdi_sio: add support for E+H FXA291

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Tim Pambor <[email protected]>

commit fad0fd120e29041b3e6cdf41bb12e3184fb524a2 upstream.

The Commubox FXA291 by Endress+Hauser AG is a USB serial converter based on FT232B which is used to communicate with field devices.

It enumerates using the FTDI vendor ID and a custom PID.

usb 1-9: New USB device found, idVendor=0403, idProduct=e510, bcdDevice= 4.00 usb 1-9: New USB device strings: Mfr=1, Product=2, SerialNumber=0 usb 1-9: Product: FXA291
usb 1-9: Manufacturer: Endress+Hauser
usb 1-9: SerialNumber: 00000000
ftdi_sio 1-9:1.0: FTDI USB Serial Device converter detected
usb 1-9: Detected FT232B
usb 1-9: FTDI USB Serial Device converter now attached to ttyUSB0

---
 drivers/usb/serial/ftdi_sio.c     |    2 ++
 drivers/usb/serial/ftdi_sio_ids.h |    5 +++++
 2 files changed, 7 insertions(+)
drivers/usb/serial/ftdi_sio.c +2 -0
@@ -1073,6 +1073,8 @@ static const struct usb_device_id id_tab
 	{ USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602E_PID, 3) },
 	/* Abacus Electrics */
 	{ USB_DEVICE(FTDI_VID, ABACUS_OPTICAL_PROBE_PID) },
+	/* Endress+Hauser AG devices */
+	{ USB_DEVICE(FTDI_VID, FTDI_EH_FXA291_PID) },
 	{ }					/* Terminating entry */
 };
 
drivers/usb/serial/ftdi_sio_ids.h +5 -0
@@ -314,6 +314,11 @@
 #define FTDI_ELV_UIO88_PID	0xFB5F	/* USB-I/O Interface (UIO 88) */
 
 /*
+ * Endress+Hauser AG product ids (FTDI_VID)
+ */
+#define FTDI_EH_FXA291_PID	0xE510
+
+/*
  * EVER Eco Pro UPS (http://www.ever.com.pl/)
  */
 
author maintainer
#154 lore raw

PATCH 154/744 USB: serial: io_edgeport: cap received transmit credits

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sunho Park <[email protected]>

commit faaddd811c5099f11a5f52e68a6b31a5898cda4f upstream.

The interrupt-status packet reports transmit credits returned by the device. edge_interrupt_callback() adds the 16-bit value to txCredits without checking maxTxCredits.

edge_write() uses txCredits minus the software FIFO count as the amount of data that fits. Since the FIFO is allocated with maxTxCredits bytes, txCredits exceeding maxTxCredits can cause OOB write in ring buffer.

Cap accumulated credits at maxTxCredits. Conforming devices should never hit the cap.

Fixes 1da177e4c3f4 ("Linux-2.6.12-rc2")
Assisted-by Codex:GPT-5
---
 drivers/usb/serial/io_edgeport.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/usb/serial/io_edgeport.c +2 -1
@@ -646,7 +646,8 @@ static void edge_interrupt_callback(stru
 				if (edge_port && edge_port->open) {
 					spin_lock_irqsave(&edge_port->ep_lock,
 							  flags);
-					edge_port->txCredits += txCredits;
+					edge_port->txCredits = min(edge_port->txCredits + txCredits,
+								   edge_port->maxTxCredits);
 					spin_unlock_irqrestore(&edge_port->ep_lock,
 							       flags);
 					dev_dbg(dev, "%s - txcredits for port%d = %d\n",
author maintainer
#155 lore raw

PATCH 155/744 USB: serial: keyspan_pda: fix data loss on receive throttling

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Johan Hovold <[email protected]>

commit 42a97c0480f96a2977e6d51ce512adc780f1ef5d upstream.

Killing the interrupt-in urb when the line disciple requests throttling may lead to data loss if an ongoing transfer is cancelled.

Instead set a flag to prevent the completion handler from resubmitting the urb until the port is unthrottled.

Fixes 1da177e4c3f4 ("Linux-2.6.12-rc2")
---
 drivers/usb/serial/keyspan_pda.c |   44 +++++++++++++++++++++++++++++++--------
 1 file changed, 35 insertions(+), 9 deletions(-)
drivers/usb/serial/keyspan_pda.c +35 -9
@@ -35,6 +35,8 @@ struct keyspan_pda_private {
 	struct work_struct	unthrottle_work;
 	struct usb_serial	*serial;
 	struct usb_serial_port	*port;
+	bool			throttled;
+	bool			throttle_req;
 };
 
 static int keyspan_pda_write_start(struct usb_serial_port *port);
@@ -150,6 +152,7 @@ static void keyspan_pda_rx_interrupt(str
 	int retval;
 	int status = urb->status;
 	struct keyspan_pda_private *priv;
+	bool throttled = false;
 	unsigned long flags;
 
 	priv = usb_get_serial_port_data(port);
@@ -211,16 +214,24 @@ static void keyspan_pda_rx_interrupt(str
 	}
 
 exit:
-	retval = usb_submit_urb(urb, GFP_ATOMIC);
-	if (retval)
-		dev_err(&port->dev,
-			"%s - usb_submit_urb failed with result %d\n",
-			__func__, retval);
+	spin_lock_irqsave(&port->lock, flags);
+	if (priv->throttle_req) {
+		priv->throttled = true;
+		throttled = true;
+	}
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	if (!throttled) {
+		retval = usb_submit_urb(urb, GFP_ATOMIC);
+		if (retval)
+			dev_err(&port->dev, "failed to resubmit in urb: %d\n", retval);
+	}
 }
 
 static void keyspan_pda_rx_throttle(struct tty_struct *tty)
 {
 	struct usb_serial_port *port = tty->driver_data;
+	struct keyspan_pda_private *priv = usb_get_serial_port_data(port);
 
 	/*
 	 * Stop receiving characters. We just turn off the URB request, and
@@ -230,16 +241,29 @@ static void keyspan_pda_rx_throttle(stru
 	 * send an XOFF, although it might make sense to foist that off upon
 	 * the device too.
 	 */
-	usb_kill_urb(port->interrupt_in_urb);
+	spin_lock_irq(&port->lock);
+	priv->throttle_req = true;
+	spin_unlock_irq(&port->lock);
 }
 
 static void keyspan_pda_rx_unthrottle(struct tty_struct *tty)
 {
 	struct usb_serial_port *port = tty->driver_data;
+	struct keyspan_pda_private *priv = usb_get_serial_port_data(port);
+	bool throttled;
+	int ret;
+
+	spin_lock_irq(&port->lock);
+	throttled = priv->throttled;
+	priv->throttled = false;
+	priv->throttle_req = false;
+	spin_unlock_irq(&port->lock);
 
-	/* just restart the receive interrupt URB */
-	if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL))
-		dev_dbg(&port->dev, "usb_submit_urb(read urb) failed\n");
+	if (throttled) {
+		ret = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+		if (ret)
+			dev_err(&port->dev, "failed to submit in urb: %d\n", ret);
+	}
 }
 
 static speed_t keyspan_pda_setbaud(struct usb_serial *serial, speed_t baud)
@@ -579,6 +603,8 @@ static int keyspan_pda_open(struct tty_s
 
 	spin_lock_irq(&port->lock);
 	priv->tx_room = rc;
+	priv->throttled = false;
+	priv->throttle_req = false;
 	spin_unlock_irq(&port->lock);
 
 	rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
author maintainer
#156 lore raw

PATCH 156/744 USB: serial: option: add TDTECH MT5710-CN

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Chukun Pan <[email protected]>

commit 55645e4f3c6022ffb160ad3617d2b624eaa38501 upstream.

Add support for the TDTECH MT5710-CN (5G redcap) module based on the Huawei HiSilicon Balong chip.

T:  Bus=01 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#=  3 Spd=480  MxCh= 0
D:  Ver= 2.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=3466 ProdID=3301 Rev=ff.ff
S:  Manufacturer=TD Tech Ltd.
S:  Product=TDTECH MT571X
S:  SerialNumber=0123456789ABCDEF
C:* #Ifs= 6 Cfg#= 1 Atr=c0 MxPwr=  0mA
A:  FirstIf#= 0 IfCount= 2 Cls=02(comm.) Sub=0d Prot=00
I:* If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=0d Prot=00 Driver=cdc_ncm
E:  Ad=82(I) Atr=03(Int.) MxPS=  16 Ivl=32ms
I:  If#= 1 Alt= 0 #EPs= 0 Cls=0a(data ) Sub=00 Prot=01 Driver=cdc_ncm
I:* If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=01 Driver=cdc_ncm
E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=06 Prot=13 Driver=option
E:  Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
I:* If#= 3 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=06 Prot=12 Driver=option
E:  Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
I:* If#= 4 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=06 Prot=1c Driver=option
E:  Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
I:* If#= 5 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=06 Prot=14 Driver=option
E:  Ad=86(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms

Interface: ECM / NCM + DIAG + AT + SERIAL + GPS

---
 drivers/usb/serial/option.c |    1 +
 1 file changed, 1 insertion(+)
drivers/usb/serial/option.c +1 -0
@@ -2497,6 +2497,7 @@ static const struct usb_device_id option
 	  .driver_info = RSVD(5) },
 	{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x1003, 0xff),			/* Rolling RW135R-GL (laptop MBIM) */
 	  .driver_info = RSVD(5) },
+	{ USB_DEVICE_INTERFACE_CLASS(0x3466, 0x3301, 0xff) },			/* TDTECH MT5710-CN */
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x30) },	/* NetPrisma LCUK54-WWD for Global */
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0x00, 0x40) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x40) },
author maintainer
#157 lore raw

PATCH 157/744 usb: typec: ucsi: Detect and skip duplicate altmodes from buggy firmware

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Chia-Lin Kao (AceLan) <[email protected]>

commit 67c92c6419ea6dbc5b1f3e9691aecea956e3e81c upstream.

Some firmware implementations incorrectly return the same altmode multiple times at different offsets when queried via UCSI_GET_ALTERNATE_MODES. This causes sysfs duplicate filename errors and kernel call traces when the driver attempts to register the same altmode twice:

sysfs: cannot create duplicate filename '/devices/.../typec/port0/port0.0/partner' typec-thunderbolt port0-partner.1: failed to create symlinks typec-thunderbolt port0-partner.1: probe with driver typec-thunderbolt failed with error -17

The matching rules differ by recipient:

- UCSI_RECIPIENT_CON (port) and UCSI_RECIPIENT_SOP_P (plug):
Two altmodes with identical SVID and VDO are byte-for-byte duplicates and the second has no observable function, so drop it.

- UCSI_RECIPIENT_SOP (partner):
The typec class binds each partner altmode to a port altmode of the same SVID via altmode_match()/device_find_child(), which returns the first port altmode with a matching SVID. If the partner advertises more altmodes for SVID X than the port advertises, the surplus partner altmode(s) collapse onto an already-paired port altmode and trigger the
"duplicate filename .../partner" sysfs error during typec_altmode_create_links(). Use the port-side altmode count for SVID X as the authoritative cap and reject any partner altmode that would exceed it. This preserves legitimate multi-Mode partner altmodes (vendor SVIDs that the port really does advertise more than once) while filtering the firmware-generated duplicates that have no port counterpart, and is therefore stricter than a plain SVID+VDO comparison (which still admits the Thunderbolt case where firmware reports the same SVID twice with different VDOs) without being over-broad like a plain SVID match (which would falsely drop legitimate vendor multi-Mode entries).

If a duplicate is detected, skip it and emit a clean warning instead of generating a kernel call trace:

ucsi_acpi USBC000:00: con2: Firmware bug: duplicate partner altmode SVID 0x8087 at offset 1, ignoring. ucsi_acpi USBC000:00: con2: VDO mismatch: 0x8087a043 vs 0x00000001

The duplicate detection logic lives in a reusable helper ucsi_altmode_is_duplicate() and is invoked from ucsi_register_altmodes(). It applies to all three recipient types:
partner (SOP), port (CON), and plug (SOP_P) altmodes.

Fixes a79f16efcd00 ("usb: typec: ucsi: Add support for the partner USB Modes")
Cc stable <[email protected]>

unchanged: still SVID+VDO exact-dup match.

---
 drivers/usb/typec/ucsi/ucsi.c |  132 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 132 insertions(+)
drivers/usb/typec/ucsi/ucsi.c +132 -0
@@ -498,6 +498,129 @@ err:
 	return ret;
 }
 
+static void ucsi_dump_duplicate_altmode(struct ucsi_connector *con,
+					u8 recipient, u16 svid,
+					u32 existing_vdo, u32 new_vdo,
+					int offset)
+{
+	static const char * const recipient_names[] = {
+		[UCSI_RECIPIENT_CON]    = "port",
+		[UCSI_RECIPIENT_SOP]    = "partner",
+		[UCSI_RECIPIENT_SOP_P]  = "plug",
+		[UCSI_RECIPIENT_SOP_PP] = "cable plug prime",
+	};
+
+	dev_warn(con->ucsi->dev,
+		 "con%d: Firmware bug: duplicate %s altmode SVID 0x%04x at offset %d, ignoring but please contact the BIOS vendor to fix this issue.\n",
+		 con->num, recipient_names[recipient], svid, offset);
+
+	if (existing_vdo != new_vdo)
+		dev_warn(con->ucsi->dev,
+			 "con%d: VDO mismatch: 0x%08x vs 0x%08x\n",
+			 con->num, existing_vdo, new_vdo);
+}
+
+/* Count altmodes in @altmodes that advertise @svid. */
+static int ucsi_altmode_count_svid(struct typec_altmode **altmodes, u16 svid)
+{
+	int count = 0;
+	int k;
+
+	for (k = 0; k < UCSI_MAX_ALTMODES; k++) {
+		if (!altmodes[k])
+			break;
+		if (altmodes[k]->svid == svid)
+			count++;
+	}
+
+	return count;
+}
+
+/*
+ * Check if an altmode is a duplicate. Some firmware implementations
+ * incorrectly return the same altmode multiple times, causing sysfs errors.
+ * Returns true if the altmode should be skipped.
+ *
+ * The matching rules differ by recipient:
+ *
+ *   - UCSI_RECIPIENT_CON (port) and UCSI_RECIPIENT_SOP_P (plug):
+ *     Two altmodes with identical SVID and VDO are byte-for-byte duplicates
+ *     and the second has no observable function. Drop them.
+ *
+ *   - UCSI_RECIPIENT_SOP (partner):
+ *     The typec class binds each partner altmode to a port altmode of the
+ *     same SVID via altmode_match()/device_find_child(), which returns the
+ *     first port altmode with a matching SVID. If the partner advertises
+ *     more altmodes for SVID X than the port advertises, the surplus
+ *     partner altmode(s) collapse onto an already-paired port altmode and
+ *     trigger a "duplicate filename .../partner" sysfs error during
+ *     typec_altmode_create_links(). Use the port-side altmode count for
+ *     SVID X as the authoritative cap and reject any partner altmode that
+ *     would exceed it. This preserves legitimate multi-Mode partner
+ *     altmodes (e.g. vendor SVIDs that the port really does advertise
+ *     twice) while filtering the firmware-generated duplicates that have
+ *     no port counterpart.
+ */
+static bool ucsi_altmode_is_duplicate(struct ucsi_connector *con, u8 recipient,
+				      const struct ucsi_altmode *alt_batch, int batch_idx,
+				      u16 svid, u32 vdo, int offset)
+{
+	struct typec_altmode **altmodes;
+	int port_count, partner_count;
+	int k;
+
+	/* Check for duplicates within the current batch first */
+	for (k = 0; k < batch_idx; k++) {
+		if (alt_batch[k].svid == svid && alt_batch[k].mid == vdo) {
+			ucsi_dump_duplicate_altmode(con, recipient, svid,
+						    vdo, vdo, offset);
+			return true;
+		}
+	}
+
+	switch (recipient) {
+	case UCSI_RECIPIENT_SOP:
+		/*
+		 * Cap partner altmodes per SVID by the port-side count:
+		 * any further partner altmode for that SVID would alias an
+		 * already-paired port altmode and break typec sysfs.
+		 */
+		port_count = ucsi_altmode_count_svid(con->port_altmode, svid);
+		partner_count = ucsi_altmode_count_svid(con->partner_altmode,
+							svid);
+		if (port_count && partner_count >= port_count) {
+			ucsi_dump_duplicate_altmode(con, recipient, svid,
+						    con->partner_altmode[partner_count - 1]->vdo,
+						    vdo, offset);
+			return true;
+		}
+		return false;
+	case UCSI_RECIPIENT_CON:
+		altmodes = con->port_altmode;
+		break;
+	case UCSI_RECIPIENT_SOP_P:
+		altmodes = con->plug_altmode;
+		break;
+	default:
+		return false;
+	}
+
+	/* CON and SOP_P: drop only exact SVID+VDO duplicates. */
+	for (k = 0; k < UCSI_MAX_ALTMODES; k++) {
+		if (!altmodes[k])
+			break;
+
+		if (altmodes[k]->svid != svid || altmodes[k]->vdo != vdo)
+			continue;
+
+		ucsi_dump_duplicate_altmode(con, recipient, svid,
+					    altmodes[k]->vdo, vdo, offset);
+		return true;
+	}
+
+	return false;
+}
+
 static int
 ucsi_register_altmodes_nvidia(struct ucsi_connector *con, u8 recipient)
 {
@@ -622,6 +745,15 @@ static int ucsi_register_altmodes(struct
 			if (!alt[j].svid)
 				return 0;
 
+			/*
+			 * Check for duplicates in current batch and already
+			 * registered altmodes. Skip if duplicate found.
+			 */
+			if (ucsi_altmode_is_duplicate(con, recipient, alt, j,
+						      alt[j].svid, alt[j].mid,
+						      i - num + j))
+				continue;
+
 			memset(&desc, 0, sizeof(desc));
 			desc.vdo = alt[j].mid;
 			desc.svid = alt[j].svid;
author maintainer
#158 lore raw

PATCH 158/744 usb: typec: ucsi: Add duplicate detection to nvidia registration path

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Chia-Lin Kao (AceLan) <[email protected]>

commit f1aa17f72f9b9589bd724dc826c5b17d164193d1 upstream.

Extend the duplicate altmode detection to ucsi_register_altmodes_nvidia() which is used when a driver provides the update_altmodes() callback.

This ensures all drivers benefit from duplicate detection, whether they use the standard registration path or the nvidia path with update_altmodes callback.

Without this fix, drivers using the nvidia path (like yoga_c630) would still encounter duplicate altmode registration errors from buggy firmware.

Fixes a79f16efcd00 ("usb: typec: ucsi: Add support for the partner USB Modes")
Cc stable <[email protected]>
---
 drivers/usb/typec/ucsi/ucsi.c |   26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)
drivers/usb/typec/ucsi/ucsi.c +16 -10
@@ -675,19 +675,25 @@ ucsi_register_altmodes_nvidia(struct ucs
 
 	/* now register altmodes */
 	for (i = 0; i < max_altmodes; i++) {
-		memset(&desc, 0, sizeof(desc));
-		if (multi_dp) {
-			desc.svid = updated[i].svid;
-			desc.vdo = updated[i].mid;
-		} else {
-			desc.svid = orig[i].svid;
-			desc.vdo = orig[i].mid;
-		}
-		desc.roles = TYPEC_PORT_DRD;
+		struct ucsi_altmode *altmode_array = multi_dp ? updated : orig;
 
-		if (!desc.svid)
+		if (!altmode_array[i].svid)
 			return 0;
 
+		/*
+		 * Check for duplicates in current array and already
+		 * registered altmodes. Skip if duplicate found.
+		 */
+		if (ucsi_altmode_is_duplicate(con, recipient, altmode_array, i,
+					      altmode_array[i].svid,
+					      altmode_array[i].mid, i))
+			continue;
+
+		memset(&desc, 0, sizeof(desc));
+		desc.svid = altmode_array[i].svid;
+		desc.vdo = altmode_array[i].mid;
+		desc.roles = TYPEC_PORT_DRD;
+
 		ret = ucsi_register_altmode(con, &desc, recipient);
 		if (ret)
 			return ret;
author maintainer
#159 lore raw

PATCH 159/744 drm/amd/display: Fix ISM dc_lock deadlock during suspend

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ray Wu <[email protected]>

[ Upstream commit 3714fe242592e3699ac5e2c19d68b275a210be7d ]

[Why]
System hang observed during suspend/resume while video is playing. amdgpu_dm_ism_disable() is called under dc_lock and waits for ISM delayed work via disable_delayed_work_sync(). The work handlers themselves take dc_lock, producing an ABBA deadlock when a worker is in flight at suspend time.

[How]
Split the disable path into two phases with opposite locking contracts:
1. amdgpu_dm_ism_disable() -- quiesces workers, must NOT hold dc_lock.
2. amdgpu_dm_ism_force_full_power() (new) -- drives the ISM FSM back to FULL_POWER_RUNNING, must hold dc_lock.

---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 25 +++++++--
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c | 56 ++++++++++++++++---
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_ism.h |  1 +
 3 files changed, 70 insertions(+), 12 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +21 -4
index 1ecd7bef9ed850..45951d47ed58c8 100644
@@ -2260,9 +2260,16 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
 		adev->dm.idle_workqueue = NULL;
 	}
 
-	/* Disable ISM before dc_destroy() invalidates dm->dc */
+	/*
+	 * Disable ISM before dc_destroy() invalidates dm->dc.
+	 *
+	 * Quiesce workers first without dc_lock (they take dc_lock
+	 * themselves, so syncing under it would deadlock), then drive the
+	 * FSM back to FULL_POWER_RUNNING under dc_lock.
+	 */
+	amdgpu_dm_ism_disable(&adev->dm);
 	scoped_guard(mutex, &adev->dm.dc_lock)
-		amdgpu_dm_ism_disable(&adev->dm);
+		amdgpu_dm_ism_force_full_power(&adev->dm);
 
 	amdgpu_dm_destroy_drm_device(&adev->dm);
 
@@ -3290,9 +3297,14 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block)
 	if (amdgpu_in_reset(adev)) {
 		enum dc_status res;
 
+		/* Quiesce ISM workers before taking dc_lock (workers take
+		 * dc_lock themselves; syncing under it would deadlock).
+		 */
+		amdgpu_dm_ism_disable(dm);
+
 		mutex_lock(&dm->dc_lock);
 
-		amdgpu_dm_ism_disable(dm);
+		amdgpu_dm_ism_force_full_power(dm);
 		dc_allow_idle_optimizations(adev->dm.dc, false);
 
 		dm->cached_dc_state = dc_state_create_copy(dm->dc->current_state);
@@ -3326,8 +3338,13 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block)
 
 	amdgpu_dm_irq_suspend(adev);
 
+	/*
+	 * Quiesce ISM workers before taking dc_lock (workers take dc_lock
+	 * themselves; syncing under it would deadlock).
+	 */
+	amdgpu_dm_ism_disable(dm);
 	scoped_guard(mutex, &dm->dc_lock)
-		amdgpu_dm_ism_disable(dm);
+		amdgpu_dm_ism_force_full_power(dm);
 
 	hpd_rx_irq_work_suspend(dm);
 
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c +48 -8

82 lines not on this page · raw message

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.h +1 -0
index fde0ddc8d4e4bc..964408cd9a839c 100644
@@ -146,6 +146,7 @@ void amdgpu_dm_ism_fini(struct amdgpu_dm_ism *ism);
 void amdgpu_dm_ism_commit_event(struct amdgpu_dm_ism *ism,
 				enum amdgpu_dm_ism_event event);
 void amdgpu_dm_ism_disable(struct amdgpu_display_manager *dm);
+void amdgpu_dm_ism_force_full_power(struct amdgpu_display_manager *dm);
 void amdgpu_dm_ism_enable(struct amdgpu_display_manager *dm);
 
 #endif
Signature · 1 line
2.53.0
author maintainer
#160 lore raw

PATCH 160/744 drm/amd/display: Fix preferred link rate for NUTMEG

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Timur Kristóf <[email protected]>

[ Upstream commit 9fb646bc4d87f62bcbf0a7ea326430eb802c475c ]

When there is a preferred link rate setting, it needs to be applied to both the current and initial link rate. This was regressed by a "coding style" fix, which caused the current link rate to not respect the preferred value.

This commit restores the functionality of NUTMEG, the DP bridge encoder found on old APUs such as Kaveri.

Fixes a62346043a89 ("drm/amd/display: Fix coding style issue")
Cc Chuanyu Tseng <[email protected]>
(cherry picked from commit e78b0a367f8690b682029d90e75308dc84ed51de)
---
 .../drm/amd/display/dc/link/protocols/link_dp_capability.c    | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +3 -1
index 782a45caa13d4a..c9c76b8c3e3ba2 100644
@@ -750,8 +750,10 @@ static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_setting
 	if (req_bw > dp_link_bandwidth_kbps(link, &link->verified_link_cap))
 		return false;
 
-	if (link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN)
+	if (link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN) {
 		initial_link_setting.link_rate = link->preferred_link_setting.link_rate;
+		current_link_setting.link_rate = link->preferred_link_setting.link_rate;
+	}
 
 	/* search for the minimum link setting that:
 	 * 1. is supported according to the link training result
Signature · 1 line
2.53.0
author maintainer
#161 lore raw

PATCH 161/744 drm/amd/display: Add dp_skip_rbr flag for NUTMEG

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Timur Kristóf <[email protected]>

[ Upstream commit e39b7cf5c62e027af166772e46382356ecb45c36 ]

No functional changes. Just clean up a conceptual mismatch.

Based on feedback on the NUTMEG code in DC, the preferred_link_setting is meant to force the DP link to a specific setting, meaning both the link rate and lane count should be locked to an exact value. What NUTMEG needs is a lower bound on the link rate, which is not the same concept.

Implement this as a HW workaround flag instead.

(cherry picked from commit 871ceb853841bcaa4e6cec3723b16c4887a760be)
---
 drivers/gpu/drm/amd/display/dc/dc.h                         | 2 ++
 drivers/gpu/drm/amd/display/dc/link/link_detection.c        | 2 +-
 .../drm/amd/display/dc/link/protocols/link_dp_capability.c  | 6 +++---
 3 files changed, 6 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/display/dc/dc.h +2 -0
index 55152f12af48be..61a28e287c1b98 100644
@@ -1727,6 +1727,8 @@ struct dc_scratch_space {
 		bool dp_skip_DID2;
 		bool dp_skip_reset_segment;
 		bool dp_skip_fs_144hz;
+		/* Some DP bridges don't work with RBR and must use HBR. */
+		bool dp_skip_rbr;
 		bool dp_mot_reset_segment;
 		/* Some USB4 docks do not handle turning off MST DSC once it has been enabled. */
 		bool dpia_mst_dsc_always_on;
drivers/gpu/drm/amd/display/dc/link/link_detection.c +1 -1
index 794dd6a9591830..faf33e9b1c6f37 100644
@@ -621,7 +621,7 @@ static bool detect_dp(struct dc_link *link,
 		link->dpcd_caps.sink_count.bits.SINK_COUNT = 1;
 		/* NUTMEG requires that we use HBR, doesn't work with RBR. */
 		if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_00001A)
-			link->preferred_link_setting.link_rate = LINK_RATE_HIGH;
+			link->wa_flags.dp_skip_rbr = true;
 	}
 
 	return true;
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +3 -3
index c9c76b8c3e3ba2..fe8420b803eeda 100644
@@ -750,9 +750,9 @@ static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_setting
 	if (req_bw > dp_link_bandwidth_kbps(link, &link->verified_link_cap))
 		return false;
 
-	if (link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN) {
-		initial_link_setting.link_rate = link->preferred_link_setting.link_rate;
-		current_link_setting.link_rate = link->preferred_link_setting.link_rate;
+	if (link->wa_flags.dp_skip_rbr) {
+		initial_link_setting.link_rate = LINK_RATE_HIGH;
+		current_link_setting.link_rate = LINK_RATE_HIGH;
 	}
 
 	/* search for the minimum link setting that:
Signature · 1 line
2.53.0
author maintainer
#162 lore raw

PATCH 162/744 wifi: mwifiex: fix freeze for 60 seconds caused by request_firmware

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Georgi Valkov <[email protected]>

[ Upstream commit 121a96c5a0db8d18e2ba2cb89660cca8a40508fe ]

Fix regression in rgpower table loading, caused by using request_firmware(): when the requested firmware does not exist, e.g. nxp/rgpower_WW.bin does not exist on OpenWRT builds for WRT3200ACM, request_firmware() falls back to firmware_fallback_sysfs(), which expects the firmware to be provided by user space using SYSFS. No such utility is provided in this configuration, so the entire system locks up for 60 seconds, until the request times out. During this time, no other log messages are observed, and the device does not respond to commands over UART.

The request_firmware() call is performed in the following context:
current->comm kworker/1:2 in_task 1 irqs_disabled 0 in_atomic 0

Fixed by using request_firmware_direct(). This prevents fallback to SYSFS, and avoids delay. The rgpower table is optional. The driver falls back to the device tree power table if the firmware is not present.

The error code is printed for debugging and returned to the caller, which only cares for success or failure, so there are no side effects.

Fixes 7b6f16a25806 ("wifi: mwifiex: add rgpower table loading support")
---
 drivers/net/wireless/marvell/mwifiex/sta_ioctl.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)
drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +8 -6
index a6550548d3b435..9460d5352b234e 100644
@@ -196,6 +196,7 @@ static int mwifiex_request_rgpower_table(struct mwifiex_private *priv)
 	struct mwifiex_adapter *adapter = priv->adapter;
 	char rgpower_table_name[30];
 	char country_code[3];
+	int ret;
 
 	strscpy(country_code, domain_info->country_code, sizeof(country_code));
 
@@ -214,16 +215,17 @@ static int mwifiex_request_rgpower_table(struct mwifiex_private *priv)
 		adapter->rgpower_data = NULL;
 	}
 
-	if ((request_firmware(&adapter->rgpower_data, rgpower_table_name,
-			      adapter->dev))) {
+	ret = request_firmware_direct(&adapter->rgpower_data, rgpower_table_name,
+				      adapter->dev);
+
+	if (ret) {
 		mwifiex_dbg(
 			adapter, INFO,
-			"info: %s: failed to request regulatory power table\n",
-			__func__);
-		return -EIO;
+			"info: %s: failed to request regulatory power table: %d\n",
+			__func__, ret);
 	}
 
-	return 0;
+	return ret;
 }
 
 static int mwifiex_dnld_rgpower_table(struct mwifiex_private *priv)
Signature · 1 line
2.53.0
author maintainer
#163 lore raw

PATCH 163/744 RISC-V: KVM: Serialize virtual interrupt pending state updates

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Xie Bo <[email protected]>

commit d024a0a7879e6f37c0152aacf6d8e37b214a1738 upstream.

KVM RISC-V tracks guest local interrupt state with two bitmaps:

- irqs_pending: interrupts that should be visible to the guest
- irqs_pending_mask: interrupts whose pending state changed

The current code updates those bitmaps with independent atomic bitops and assumes a multiple-producer, single-consumer protocol. That model does not actually hold.

kvm_riscv_vcpu_sync_interrupts() is not a pure consumer. When the guest changes guest-visible HVIP state, sync_interrupts() writes both irqs_pending and irqs_pending_mask to reflect the new guest state back into KVM state. As a result, irqs_pending and irqs_pending_mask form a single logical state transition, but they are not updated atomically as a pair.

This allows a race where a newly injected interrupt is lost. For example:

CPU0 CPU1
---- ----
kvm_riscv_vcpu_set_interrupt(VS_SOFT)
set_bit(VS_SOFT, irqs_pending)
kvm_riscv_vcpu_sync_interrupts()
sees guest-cleared HVIP.VSSIP sets irqs_pending_mask clear_bit(IRQ_VS_SOFT, irqs_pending)
set_bit(VS_SOFT, irqs_pending_mask)
kvm_vcpu_kick()

After that interleaving, a later flush can update HVIP without VSSIP even though a new virtual interrupt was injected. In practice, the guest can remain blocked in WFI with work pending.

The same pending/mask protocol is shared by VS soft interrupts, PMU overflow delivery, and AIA high interrupt synchronization, so the race is not limited to one interrupt source.

Fix this by serializing all updates to irqs_pending and irqs_pending_mask with a per-vCPU raw spinlock. This keeps the pending bit and the dirty mask as one state transition across:

- set/unset interrupt
- guest HVIP sync
- interrupt flush to guest CSR state
- vCPU reset
- AIA CSR writes that clear dirty state

Use non-atomic bitmap operations while holding the lock. Hold the lock across the AIA sync, flush, and pending checks as well, so both bitmap words share the same serialization domain.

This intentionally replaces the existing lockless protocol instead of trying to repair it with additional barriers. The problem is not memory ordering on a single field; it is that two separate bitmaps encode one shared state machine while both producers and sync paths can modify them. A per-vCPU raw spinlock keeps the fix small, local, and suitable for backporting.

Fixes cce69aff689e ("RISC-V: KVM: Implement VCPU interrupts and requests handling")

[ Adapted for 7.1.y: place the new 'unsigned long flags;' declaration in
kvm_riscv_vcpu_general_set_csr() explicitly. A direct apply anchors it in kvm_riscv_vcpu_general_get_csr(), whose prologue is byte-identical, leaving 'flags' undeclared at its use site. ]

---
 arch/riscv/include/asm/kvm_host.h | 10 ++---
 arch/riscv/kvm/aia.c              | 35 ++++++++++++----
 arch/riscv/kvm/vcpu.c             | 68 ++++++++++++++++++++++---------
 arch/riscv/kvm/vcpu_onereg.c      |  8 +++-
 4 files changed, 87 insertions(+), 34 deletions(-)
arch/riscv/include/asm/kvm_host.h +5 -5
index 75b0a951c1bc6f..97e42645cbabee 100644
@@ -207,13 +207,13 @@ struct kvm_vcpu_arch {
 	/*
 	 * VCPU interrupts
 	 *
-	 * We have a lockless approach for tracking pending VCPU interrupts
-	 * implemented using atomic bitops. The irqs_pending bitmap represent
-	 * pending interrupts whereas irqs_pending_mask represent bits changed
-	 * in irqs_pending. Our approach is modeled around multiple producer
-	 * and single consumer problem where the consumer is the VCPU itself.
+	 * The irqs_pending bitmap represents pending interrupts whereas
+	 * irqs_pending_mask represents bits changed in irqs_pending. Updates
+	 * to these bitmaps are serialized so vcpu interrupt sync/flush cannot
+	 * drop a newly injected interrupt while syncing guest-visible HVIP.
 	 */
 #define KVM_RISCV_VCPU_NR_IRQS	64
+	raw_spinlock_t irqs_pending_lock;
 	DECLARE_BITMAP(irqs_pending, KVM_RISCV_VCPU_NR_IRQS);
 	DECLARE_BITMAP(irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS);
 
arch/riscv/kvm/aia.c +28 -7
index 5ec503288555d1..5e92fe14f79ae7 100644
@@ -51,12 +51,15 @@ void kvm_riscv_vcpu_aia_flush_interrupts(struct kvm_vcpu *vcpu)
 	struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
 	unsigned long mask, val;
 
+	lockdep_assert_held(&vcpu->arch.irqs_pending_lock);
+
 	if (!kvm_riscv_aia_available())
 		return;
 
-	if (READ_ONCE(vcpu->arch.irqs_pending_mask[1])) {
-		mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[1], 0);
-		val = READ_ONCE(vcpu->arch.irqs_pending[1]) & mask;
+	mask = vcpu->arch.irqs_pending_mask[1];
+	if (mask) {
+		vcpu->arch.irqs_pending_mask[1] = 0;
+		val = vcpu->arch.irqs_pending[1] & mask;
 
 		csr->hviph &= ~mask;
 		csr->hviph |= val;
@@ -67,6 +70,8 @@ void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu)
 {
 	struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
 
+	lockdep_assert_held(&vcpu->arch.irqs_pending_lock);
+
 	if (kvm_riscv_aia_available())
 		csr->vsieh = ncsr_read(CSR_VSIEH);
 }
@@ -75,13 +80,22 @@ void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu)
 bool kvm_riscv_vcpu_aia_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
 {
 	unsigned long seip;
+#ifdef CONFIG_32BIT
+	unsigned long flags;
+	bool pending;
+#endif
 
 	if (!kvm_riscv_aia_available())
 		return false;
 
 #ifdef CONFIG_32BIT
-	if (READ_ONCE(vcpu->arch.irqs_pending[1]) &
-	    (vcpu->arch.aia_context.guest_csr.vsieh & upper_32_bits(mask)))
+	raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
+	pending = vcpu->arch.irqs_pending[1] &
+		  (vcpu->arch.aia_context.guest_csr.vsieh &
+		   upper_32_bits(mask));
+	raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+
+	if (pending)
 		return true;
 #endif
 
@@ -205,6 +219,9 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu,
 {
 	struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
 	unsigned long regs_max = sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long);
+#ifdef CONFIG_32BIT
+	unsigned long flags;
+#endif
 
 	if (!riscv_isa_extension_available(vcpu->arch.isa, SSAIA))
 		return -ENOENT;
@@ -217,8 +234,12 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu,
 		((unsigned long *)csr)[reg_num] = val;
 
 #ifdef CONFIG_32BIT
-		if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph))
-			WRITE_ONCE(vcpu->arch.irqs_pending_mask[1], 0);
+		if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph)) {
+			raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
+			vcpu->arch.irqs_pending_mask[1] = 0;
+			raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock,
+						   flags);
+		}
 #endif
 	}
 
arch/riscv/kvm/vcpu.c +48 -20

164 lines not on this page · raw message

arch/riscv/kvm/vcpu_onereg.c +6 -2
index bb920e8923c930..2031beb9bba6e7 100644
@@ -298,6 +298,7 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
 {
 	struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
 	unsigned long regs_max = sizeof(struct kvm_riscv_csr) / sizeof(unsigned long);
+	unsigned long flags;
 
 	if (reg_num >= regs_max)
 		return -ENOENT;
@@ -311,8 +312,11 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
 
 	((unsigned long *)csr)[reg_num] = reg_val;
 
-	if (reg_num == KVM_REG_RISCV_CSR_REG(sip))
-		WRITE_ONCE(vcpu->arch.irqs_pending_mask[0], 0);
+	if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
+		raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
+		vcpu->arch.irqs_pending_mask[0] = 0;
+		raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+	}
 
 	return 0;
 }
Signature · 1 line
2.53.0
author maintainer
#164 lore raw

PATCH 164/744 Revert "drm/amd/display: Add missing kdoc for ALLM parameters"

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

This reverts commit 994a42b890cef46cd576a3bf700f1dbd6bb21346.

---
 drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c | 2 --
 1 file changed, 2 deletions(-)
drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c +0 -2
index 614db22d62f38b..00473c6284d5cc 100644
@@ -502,8 +502,6 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
  *
  *  @stream:      contains data we may need to construct VSIF (i.e. timing_3d_format, etc.)
  *  @info_packet: output structure where to store VSIF
- *  @ALLMEnabled: indicates whether ALLM HF-VSIF should be generated
- *  @ALLMValue:   ALLM bit value to advertise in HF-VSIF
  */
 void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
 		struct dc_info_packet *info_packet)
Signature · 1 line
2.53.0
author maintainer
#165 lore raw

PATCH 165/744 usb: xhci-pci: Limit VIA VL805 DMA addressing to 36 bits

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Xincheng Zhang <[email protected]>

commit 1fc50f1ecde39feb4fccdaf4bc71aa6c0eb25c49 upstream.

The VIA VL805/806 xHCI controller advertises AC64, but fails to handle DMA addresses at or above 0x1000000000. On systems with large amounts of RAM, this can cause USB device failures when the controller is given DMA addresses beyond its usable address width.

Do not use XHCI_NO_64BIT_SUPPORT for this controller. That quirk clears the cached AC64 capability and limits DMA to 32 bits, causing unnecessary bouncing for addresses between 4GiB and 64GiB and hiding the controller's real AC64 capability from code that may need to distinguish register access width from usable DMA address width.

Track the usable DMA address width separately from the AC64 capability. Initialize the generic xhci->dma_mask_bits field to 64 and let PCI quirks reduce it for controllers with narrower DMA support. Set VIA VL805/806 to 36 bits so the DMA API only hands it addresses in the range it can handle while keeping HCCPARAMS1.AC64 visible.

---
 drivers/usb/host/xhci-pci.c |  1 +
 drivers/usb/host/xhci.c     | 15 ++++++++++-----
 drivers/usb/host/xhci.h     |  1 +
 3 files changed, 12 insertions(+), 5 deletions(-)
drivers/usb/host/xhci-pci.c +1 -0
index 585b2f3117b08a..b0377701a94042 100644
@@ -448,6 +448,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
 	if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == PCI_DEVICE_ID_VIA_VL805) {
 		xhci->quirks |= XHCI_LPM_SUPPORT;
 		xhci->quirks |= XHCI_TRB_OVERFETCH;
+		xhci->dma_mask_bits = 36;
 	}
 
 	if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
drivers/usb/host/xhci.c +10 -5
index 15346fdd66bc43..5b15eae233d3f6 100644
@@ -5469,6 +5469,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 	if (xhci->hci_version > 0x100)
 		xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2);
 
+	xhci->dma_mask_bits = 64;
 	xhci->max_slots = HCS_MAX_SLOTS(hcs_params1);
 	xhci->max_ports = min(HCS_MAX_PORTS(hcs_params1), MAX_HC_PORTS);
 	/* xhci-plat or xhci-pci might have set max_interrupters already */
@@ -5518,12 +5519,16 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 	if (xhci->quirks & XHCI_NO_64BIT_SUPPORT)
 		xhci->hcc_params &= ~BIT(0);
 
-	/* Set dma_mask and coherent_dma_mask to 64-bits,
-	 * if xHC supports 64-bit addressing */
+	/*
+	 * Set dma_mask and coherent_dma_mask to 64-bits if xHC supports
+	 * 64-bit addressing, unless a controller-specific quirk callback
+	 * limits the usable address width.
+	 */
 	if ((xhci->hcc_params & HCC_64BIT_ADDR) &&
-			!dma_set_mask(dev, DMA_BIT_MASK(64))) {
-		xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
-		dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
+	    !dma_set_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits))) {
+		xhci_dbg(xhci, "Enabling %u-bit DMA addresses.\n",
+			 xhci->dma_mask_bits);
+		dma_set_coherent_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits));
 	} else {
 		/*
 		 * This is to avoid error in cases where a 32-bit USB
drivers/usb/host/xhci.h +1 -0
index aeecd301f20707..d0f14fc2324572 100644
@@ -1524,6 +1524,7 @@ struct xhci_hcd {
 	/* imod_interval in ns (I * 250ns) */
 	u32		imod_interval;
 	u32		page_size;
+	unsigned int	dma_mask_bits;
 	/* MSI-X/MSI vectors */
 	int		nvecs;
 	/* optional clocks */
Signature · 1 line
2.53.0
author maintainer
#166 lore raw

PATCH 166/744 selftests/bpf: Adjust verifier_map_ptr for the maps excl field

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: KP Singh <[email protected]>

commit 38498c0ebacd54dbaac3513a548a13f1a8455c4e upstream.

Adding the u32 excl field at offset 32 of struct bpf_map right after the sha[SHA256_DIGEST_SIZE] hash shifts the ops pointer from offset 32 to 40. Therefore, fix up the test case.

# LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_map_ptr [...]

  #637/1   verifier_map_ptr/bpf_map_ptr: read with negative offset rejected:OK
  #637/2   verifier_map_ptr/bpf_map_ptr: read with negative offset rejected @unpriv:OK
  #637/3   verifier_map_ptr/bpf_map_ptr: write rejected:OK
  #637/4   verifier_map_ptr/bpf_map_ptr: write rejected @unpriv:OK
  #637/5   verifier_map_ptr/bpf_map_ptr: read non-existent field rejected:OK
  #637/6   verifier_map_ptr/bpf_map_ptr: read non-existent field rejected @unpriv:OK
  #637/7   verifier_map_ptr/bpf_map_ptr: read ops field accepted:OK
  #637/8   verifier_map_ptr/bpf_map_ptr: read ops field accepted @unpriv:OK

[...]
Summary: 2/18 PASSED, 0 SKIPPED, 0 FAILED

---
 tools/testing/selftests/bpf/progs/verifier_map_ptr.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
tools/testing/selftests/bpf/progs/verifier_map_ptr.c +5 -3
index e2767d27d8aaf8..d8e822d1a8bab6 100644
@@ -70,13 +70,15 @@ __naked void bpf_map_ptr_write_rejected(void)
 	: __clobber_all);
 }
 
-/* The first element of struct bpf_map is a SHA256 hash of 32 bytes, accessing
- * into this array is valid. The opts field is now at offset 33.
+/*
+ * struct bpf_map starts with the SHA256 hash sha[32] at offset 0 (a readable
+ * byte array), followed by the u32 excl field at offset 32. Reading a u32 at
+ * offset 33 runs past the end of excl and is rejected.
  */
 SEC("socket")
 __description("bpf_map_ptr: read non-existent field rejected")
 __failure
-__msg("cannot access ptr member ops with moff 32 in struct bpf_map with off 33 size 4")
+__msg("access beyond the end of member excl (mend:36) in struct bpf_map with off 33 size 4")
 __failure_unpriv
 __msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN")
 __flag(BPF_F_ANY_ALIGNMENT)
Signature · 1 line
2.53.0
author maintainer
#167 lore raw

PATCH 167/744 selftests/bpf: Keep verifier_map_ptr exercising ops pointer access

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Daniel Borkmann <[email protected]>

commit 082c412097716b93ff1365689fc4ddcd1ce8296f upstream.

sashiko complained that 38498c0ebacd ("selftests/bpf: Adjust verifier_map_ptr for the map's excl field") would slightly decrease the test coverage given before the test was against the verifier rejecting the ops pointer. Recover the old test with the right offsets and add the existing one as an additional test case.

# LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_map_ptr

  [    1.672932] bpf_testmod: module verification failed: signature and/or required key missing - tainting kernel
  #637/1   verifier_map_ptr/bpf_map_ptr: read with negative offset rejected:OK
  #637/2   verifier_map_ptr/bpf_map_ptr: read with negative offset rejected @unpriv:OK
  #637/3   verifier_map_ptr/bpf_map_ptr: write rejected:OK
  #637/4   verifier_map_ptr/bpf_map_ptr: write rejected @unpriv:OK
  #637/5   verifier_map_ptr/bpf_map_ptr: read non-existent field rejected:OK
  #637/6   verifier_map_ptr/bpf_map_ptr: read non-existent field rejected @unpriv:OK
  #637/7   verifier_map_ptr/bpf_map_ptr: read beyond excl field rejected:OK
  #637/8   verifier_map_ptr/bpf_map_ptr: read beyond excl field rejected @unpriv:OK
  #637/9   verifier_map_ptr/bpf_map_ptr: read ops field accepted:OK
  #637/10  verifier_map_ptr/bpf_map_ptr: read ops field accepted @unpriv:OK
  #637/11  verifier_map_ptr/bpf_map_ptr: r = 0, map_ptr = map_ptr + r:OK
  #637/12  verifier_map_ptr/bpf_map_ptr: r = 0, map_ptr = map_ptr + r @unpriv:OK
  #637/13  verifier_map_ptr/bpf_map_ptr: r = 0, r = r + map_ptr:OK
  #637/14  verifier_map_ptr/bpf_map_ptr: r = 0, r = r + map_ptr @unpriv:OK
  #637     verifier_map_ptr:OK
  [...]
  Summary: 2/20 PASSED, 0 SKIPPED, 0 FAILED
---
 .../selftests/bpf/progs/verifier_map_ptr.c    | 34 ++++++++++++++++---
 1 file changed, 30 insertions(+), 4 deletions(-)
tools/testing/selftests/bpf/progs/verifier_map_ptr.c +30 -4
index d8e822d1a8bab6..1661936598703c 100644
@@ -72,17 +72,43 @@ __naked void bpf_map_ptr_write_rejected(void)
 
 /*
  * struct bpf_map starts with the SHA256 hash sha[32] at offset 0 (a readable
- * byte array), followed by the u32 excl field at offset 32. Reading a u32 at
- * offset 33 runs past the end of excl and is rejected.
+ * byte array), the u32 excl field at offset 32, and the ops pointer at offset
+ * 40. Reading a u32 at offset 41 reaches into the middle of the ops pointer,
+ * i.e. a partial pointer access, which is rejected.
  */
 SEC("socket")
 __description("bpf_map_ptr: read non-existent field rejected")
 __failure
-__msg("access beyond the end of member excl (mend:36) in struct bpf_map with off 33 size 4")
+__msg("cannot access ptr member ops with moff 40 in struct bpf_map with off 41 size 4")
 __failure_unpriv
 __msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN")
 __flag(BPF_F_ANY_ALIGNMENT)
 __naked void read_non_existent_field_rejected(void)
+{
+	asm volatile ("					\
+	r6 = 0;						\
+	r1 = %[map_array_48b] ll;			\
+	r6 = *(u32*)(r1 + 41);				\
+	r0 = 1;						\
+	exit;						\
+"	:
+	: __imm_addr(map_array_48b)
+	: __clobber_all);
+}
+
+/*
+ * The u32 excl field spans offsets 32..35 (mend 36). Reading a u32 at offset
+ * 33 starts inside excl but extends past its end, which the verifier rejects
+ * as an out-of-bounds scalar access.
+ */
+SEC("socket")
+__description("bpf_map_ptr: read beyond excl field rejected")
+__failure
+__msg("access beyond the end of member excl (mend:36) in struct bpf_map with off 33 size 4")
+__failure_unpriv
+__msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN")
+__flag(BPF_F_ANY_ALIGNMENT)
+__naked void read_beyond_excl_field_rejected(void)
 {
 	asm volatile ("					\
 	r6 = 0;						\
@@ -105,7 +131,7 @@ __naked void ptr_read_ops_field_accepted(void)
 	asm volatile ("					\
 	r6 = 0;						\
 	r1 = %[map_array_48b] ll;			\
-	r6 = *(u64*)(r1 + 0);				\
+	r6 = *(u64*)(r1 + 40);				\
 	r0 = 1;						\
 	exit;						\
 "	:
Signature · 1 line
2.53.0
author maintainer
#168 lore raw

PATCH 168/744 watchdog: ni903x_wdt: Check ACPI_COMPANION() against NULL

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Rafael J. Wysocki <[email protected]>

[ Upstream commit 36e05e134ee44f9fbfcebcbcdadb5f765fccd9f0 ]

Every platform driver can be forced to match a device that doesn't match its list of device IDs because of device_match_driver_override(), so platform drivers that rely on the existence of a device's ACPI companion object need to verify its presence.

Accordingly, add a requisite ACPI_COMPANION() check against NULL to the ni903x_wdt watchdog driver.

Fixes d37ec2fbab55 ("watchdog: ni903x_wdt: Convert to a platform driver")
---
 drivers/watchdog/ni903x_wdt.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/watchdog/ni903x_wdt.c +6 -1
index 8b1b9baa914e5f..c72a9ee9cb8e19 100644
@@ -183,9 +183,14 @@ static int ni903x_acpi_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct watchdog_device *wdd;
 	struct ni903x_wdt *wdt;
+	acpi_handle handle;
 	acpi_status status;
 	int ret;
 
+	handle = ACPI_HANDLE(dev);
+	if (!handle)
+		return -ENODEV;
+
 	wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
 	if (!wdt)
 		return -ENOMEM;
@@ -193,7 +198,7 @@ static int ni903x_acpi_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, wdt);
 	wdt->dev = dev;
 
-	status = acpi_walk_resources(ACPI_HANDLE(dev), METHOD_NAME__CRS,
+	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
 				     ni903x_resources, wdt);
 	if (ACPI_FAILURE(status) || wdt->io_base == 0) {
 		dev_err(dev, "failed to get resources\n");
Signature · 1 line
2.53.0
author maintainer
#169 lore raw

PATCH 169/744 wifi: ath9k: hif_usb: dont dereference hif_dev after re-arming firmware request

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Cheng Yongkang <[email protected]>

[ Upstream commit dad9f96945d77ecd4708f730c06ef54dcd8cc057 ]

ath9k_hif_request_firmware() re-arms an asynchronous firmware load via request_firmware_nowait(), passing hif_dev as the completion context, and then still dereferences hif_dev:

	dev_info(&hif_dev->udev->dev, "ath9k_htc: Firmware %s requested\n",
		 hif_dev->fw_name);

The re-armed callback ath9k_hif_usb_firmware_cb() runs on the "events" workqueue and, when the firmware is missing, walks the retry chain into ath9k_hif_usb_firmware_fail() -> complete_all(&hif_dev->fw_done). That releases the wait_for_completion(&hif_dev->fw_done) in a concurrent ath9k_hif_usb_disconnect(), which then kfree()s hif_dev. The trailing dev_info() in the frame that re-armed the request can therefore read freed memory (hif_dev->udev, the first field of struct hif_device_usb):

  BUG: KASAN: slab-use-after-free in ath9k_hif_request_firmware
  Read of size 8 ... by task kworker/...
   ath9k_hif_request_firmware
   ath9k_hif_usb_firmware_cb           drivers/net/wireless/ath/ath9k/hif_usb.c:1247
   request_firmware_work_func
  Allocated by ...:
   ath9k_hif_usb_probe                 drivers/net/wireless/ath/ath9k/hif_usb.c
  Freed by ...:
   ath9k_hif_usb_disconnect -> kfree   drivers/net/wireless/ath/ath9k/hif_usb.c

The fw_done barrier only makes disconnect wait for the firmware chain to *terminate*; it does not protect the outer ath9k_hif_request_firmware() frame that re-armed the request and keeps touching hif_dev afterwards.

Drop the post-request dev_info(): it is the only use of hif_dev after the async request is armed, and it is purely informational (the dev_err() on the failure path runs only when request_firmware_nowait() did not arm a callback, so hif_dev is still alive there).

This was first reported by syzbot as a single, non-reproduced crash that was later auto-obsoleted, and was independently rediscovered by the reFuzz fuzzer, which produced a C reproducer (USB-gadget connect/disconnect of an ath9k_htc device whose firmware download fails). The vulnerable code is unchanged and still present in v7.1-rc6, where the slab-use-after-free reproduces under KASAN once the (sub-microsecond) race window is widened.

---
 drivers/net/wireless/ath/ath9k/hif_usb.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)
drivers/net/wireless/ath/ath9k/hif_usb.c +1 -6
index 821909b81ea917..44855ec5be7453 100644
@@ -1225,15 +1225,10 @@ static int ath9k_hif_request_firmware(struct hif_device_usb *hif_dev,
 	ret = request_firmware_nowait(THIS_MODULE, true, hif_dev->fw_name,
 				      &hif_dev->udev->dev, GFP_KERNEL,
 				      hif_dev, ath9k_hif_usb_firmware_cb);
-	if (ret) {
+	if (ret)
 		dev_err(&hif_dev->udev->dev,
 			"ath9k_htc: Async request for firmware %s failed\n",
 			hif_dev->fw_name);
-		return ret;
-	}
-
-	dev_info(&hif_dev->udev->dev, "ath9k_htc: Firmware %s requested\n",
-		 hif_dev->fw_name);
 
 	return ret;
 }
Signature · 1 line
2.53.0
author maintainer
#170 lore raw

PATCH 170/744 wifi: ath11k: fix NULL pointer dereference in ath11k_hal_srng_access_begin

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Gaole Zhang <[email protected]>

[ Upstream commit e8d85672dd7e2523f774caafba8f858384e18df7 ]

In ATH11K_QMI_EVENT_FW_READY, ATH11K_FLAG_REGISTERED is set unconditionally even when ath11k_core_qmi_firmware_ready() fails. This leaves the driver in an inconsistent state where initialization is considered complete although the firmware ready handling did not finish successfully. During the subsequent SSR, the driver enters the restart path based on this incorrect state and dereferences uninitialized srng members, resulting in a NULL pointer dereference.

Call trace:
  ath11k_hal_srng_access_begin+0xc/0x60 [ath11k] (P)
  ath11k_ce_cleanup_pipes+0x17c/0x180 [ath11k]
  ath11k_core_restart+0x40/0x168 [ath11k]

Fix this by:
- skipping firmware_ready if ATH11K_FLAG_REGISTERED is already set
- setting ATH11K_FLAG_REGISTERED only when firmware_ready succeeds
- setting ATH11K_FLAG_QMI_FAIL and aborting the FW_READY handling on error

Tested-on: WCN6750 hw1.0 AHB WLAN.MSL.2.0.c2-00204-QCAMSLSWPLZ-1

Fixes 6fe62a8cec51c ("wifi: ath11k: Add cold boot calibration support on WCN6750")
---
 drivers/net/wireless/ath/ath11k/qmi.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/net/wireless/ath/ath11k/qmi.c +8 -3
index feebbc30f3df32..a304feca70423e 100644
@@ -3295,9 +3295,14 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work)
 			clear_bit(ATH11K_FLAG_CRASH_FLUSH,
 				  &ab->dev_flags);
 			clear_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags);
-			ath11k_core_qmi_firmware_ready(ab);
-			set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags);
-
+			if (!test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) {
+				ret = ath11k_core_qmi_firmware_ready(ab);
+				if (ret) {
+					set_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags);
+					break;
+				}
+				set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags);
+			}
 			break;
 		case ATH11K_QMI_EVENT_COLD_BOOT_CAL_DONE:
 			break;
Signature · 1 line
2.53.0
author maintainer
#171 lore raw

PATCH 171/744 hwmon: (corsair-psu) Stop device IO before calling hid_hw_stop

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Edward Adam Davis <[email protected]>

[ Upstream commit 9ab8656548cd737b98d0b19c4253aff8d68e97f4 ]

hid_hw_stop() does not stop the device IO.

This results in a race condition between hid_input_report() and the point immediately following the execution of hid_device_io_start() within corsairpsu_probe(). If the probe operation fails after "io start" has been initiated, this race condition will result in a uaf vulnerability [1].

CPU0 CPU1
==== ====
corsairpsu_probe()
hid_device_io_start()
... unlock driver_input_lock
hid_hw_stop()
kfree(hidraw) __hid_input_report()
... acquire driver_input_lock hid_report_raw_event()
hidraw_report_event()
... access hidraw's list_lock // trigger uaf

Consequently, when corsairpsu_probe() fails and hid_hw_stop() needs to be executed, the io_started flag is first cleared while holding the driver_input_lock to prevent potential race conditions involving input reports.

[1]

BUG: KASAN: slab-use-after-free in rt_spin_lock+0x83/0x400 kernel/locking/spinlock_rt.c:56
Call Trace:
 hidraw_report_event+0x5d/0x3a0 drivers/hid/hidraw.c:577
 hid_report_raw_event+0x311/0x1730 drivers/hid/hid-core.c:2076
 __hid_input_report drivers/hid/hid-core.c:2152 [inline]
 hid_input_report+0x44e/0x580 drivers/hid/hid-core.c:2174
 hid_irq_in+0x47e/0x6d0 drivers/hid/usbhid/hid-core.c:286
 __usb_hcd_giveback_urb+0x3b3/0x5e0 drivers/usb/core/hcd.c:1657
 dummy_timer+0x8a9/0x47d0 drivers/usb/gadget/udc/dummy_hcd.c:2005

Allocated by task 10:
 hidraw_connect+0x57/0x430 drivers/hid/hidraw.c:606
 hid_connect+0x5bf/0x19d0 drivers/hid/hid-core.c:2277
 hid_hw_start+0xa8/0x120 drivers/hid/hid-core.c:2387
 corsairpsu_probe+0xd9/0x3c0 drivers/hwmon/corsair-psu.c:782

Freed by task 10:
 hidraw_disconnect+0x4f/0x60 drivers/hid/hidraw.c:662
 hid_disconnect drivers/hid/hid-core.c:2362 [inline]
 hid_hw_stop+0x101/0x1e0 drivers/hid/hid-core.c:2407
 corsairpsu_probe+0x327/0x3c0 drivers/hwmon/corsair-psu.c:826

Fix the problem by calling hid_device_io_stop() before calling hid_hw_stop().

[groeck: Updated subject and description;
call hid_device_io_stop() only if IO has been started]

---
 drivers/hwmon/corsair-psu.c | 1 +
 1 file changed, 1 insertion(+)
drivers/hwmon/corsair-psu.c +1 -0
index 76f3e1da68d09e..ce958cdaef58a3 100644
@@ -822,6 +822,7 @@ static int corsairpsu_probe(struct hid_device *hdev, const struct hid_device_id
 
 fail_and_close:
 	hid_hw_close(hdev);
+	hid_device_io_stop(hdev);
 fail_and_stop:
 	hid_hw_stop(hdev);
 	return ret;
Signature · 1 line
2.53.0
author maintainer
#172 lore raw

PATCH 172/744 hwmon: (corsair-cpro) Stop device IO before calling hid_hw_stop

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Guenter Roeck <[email protected]>

[ Upstream commit 94c87871b051d7ad758828a805215a2ec194512a ]

Calling hid_hw_stop() does not stop the device IO.
This results in a race condition between hid_input_report() and the point immediately following the execution of hid_device_io_start() within the driver probe function. If the probe operation fails after "io start" has been initiated, this race condition will result in a UAF vulnerability.

Fix the problem by calling hid_device_io_stop() before calling hid_hw_stop().

Fixes 40c3a44542257 ("hwmon: add Corsair Commander Pro driver")
---
 drivers/hwmon/corsair-cpro.c | 1 +
 1 file changed, 1 insertion(+)
drivers/hwmon/corsair-cpro.c +1 -0
index b6e508e43fa17f..8354a002f4c5e1 100644
@@ -645,6 +645,7 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
 out_hw_close:
 	hid_hw_close(hdev);
+	hid_device_io_stop(hdev);
 out_hw_stop:
 	hid_hw_stop(hdev);
 	return ret;
Signature · 1 line
2.53.0
author maintainer
#173 lore raw

PATCH 173/744 hwmon: (gigabyte_waterforce) Stop device IO before calling hid_hw_stop

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Guenter Roeck <[email protected]>

[ Upstream commit ff0c5c53d08274e200b48a4d53aa078265e873cb ]

Calling hid_hw_stop() does not stop the device IO.
This results in a race condition between hid_input_report() and the point immediately following the execution of hid_device_io_start() within the driver probe function. If the probe operation fails after "io start" has been initiated, this race condition will result in a UAF vulnerability.

Fix the problem by calling hid_device_io_stop() before calling hid_hw_stop().

Fixes 42ac68e3d4ba0 ("hwmon: Add driver for Gigabyte AORUS Waterforce AIO coolers")
---
 drivers/hwmon/gigabyte_waterforce.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/hwmon/gigabyte_waterforce.c +3 -1
index 27487e215bddff..4eea05f8b569c2 100644
@@ -371,13 +371,15 @@ static int waterforce_probe(struct hid_device *hdev, const struct hid_device_id
 	if (IS_ERR(priv->hwmon_dev)) {
 		ret = PTR_ERR(priv->hwmon_dev);
 		hid_err(hdev, "hwmon registration failed with %d\n", ret);
-		goto fail_and_close;
+		goto fail_and_io_stop;
 	}
 
 	waterforce_debugfs_init(priv);
 
 	return 0;
 
+fail_and_io_stop:
+	hid_device_io_stop(hdev);
 fail_and_close:
 	hid_hw_close(hdev);
 fail_and_stop:
Signature · 1 line
2.53.0
author maintainer
#174 lore raw

PATCH 174/744 hwmon: (nzxt-smart2) Stop device IO before calling hid_hw_stop

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Guenter Roeck <[email protected]>

[ Upstream commit 59d104b54b0b42e30fd2a68d24ee5c49dcc54d1e ]

Calling hid_hw_stop() does not stop the device IO.
This results in a race condition between hid_input_report() and the point immediately following the execution of hid_device_io_start() within the driver probe function. If the probe operation fails after "io start" has been initiated, this race condition will result in a UAF vulnerability.

Fix the problem by calling hid_device_io_stop() before calling hid_hw_stop().

Fixes 53e68c20aeb1e ("hwmon: add driver for NZXT RGB&Fan Controller/Smart Device v2")
---
 drivers/hwmon/nzxt-smart2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwmon/nzxt-smart2.c +1 -1
index 58ef9fa0184be4..e2316c46629d61 100644
@@ -768,7 +768,7 @@ static int nzxt_smart2_hid_probe(struct hid_device *hdev,
 
 out_hw_close:
 	hid_hw_close(hdev);
-
+	hid_device_io_stop(hdev);
 out_hw_stop:
 	hid_hw_stop(hdev);
 	return ret;
Signature · 1 line
2.53.0
author maintainer
#175 lore raw

PATCH 175/744 hwmon: (nzxt-kraken3) Stop device IO before calling hid_hw_stop

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Guenter Roeck <[email protected]>

[ Upstream commit f151d0143ac4e086f92f52328ebdbdc50933d8ef ]

Calling hid_hw_stop() does not stop the device IO.
This results in a race condition between hid_input_report() and the point immediately following the execution of hid_device_io_start() within the driver probe function. If the probe operation fails after "io start" has been initiated, this race condition will result in a UAF vulnerability.

Fix the problem by calling hid_device_io_stop() before calling hid_hw_stop().

Fixes f3b4b146eb107 ("hwmon: Add driver for NZXT Kraken X and Z series AIO CPU coolers")
---
 drivers/hwmon/nzxt-kraken3.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/hwmon/nzxt-kraken3.c +4 -2
index d00409bcab93ad..05525406c5fbb5 100644
@@ -948,7 +948,7 @@ static int kraken3_probe(struct hid_device *hdev, const struct hid_device_id *id
 	ret = kraken3_init_device(hdev);
 	if (ret < 0) {
 		hid_err(hdev, "device init failed with %d\n", ret);
-		goto fail_and_close;
+		goto fail_and_stop_io;
 	}
 
 	ret = kraken3_get_fw_ver(hdev);
@@ -960,13 +960,15 @@ static int kraken3_probe(struct hid_device *hdev, const struct hid_device_id *id
 	if (IS_ERR(priv->hwmon_dev)) {
 		ret = PTR_ERR(priv->hwmon_dev);
 		hid_err(hdev, "hwmon registration failed with %d\n", ret);
-		goto fail_and_close;
+		goto fail_and_stop_io;
 	}
 
 	kraken3_debugfs_init(priv, device_name);
 
 	return 0;
 
+fail_and_stop_io:
+	hid_device_io_stop(hdev);
 fail_and_close:
 	hid_hw_close(hdev);
 fail_and_stop:
Signature · 1 line
2.53.0
author maintainer
#176 lore raw

PATCH 176/744 watchdog: pretimeout: Fix UAF in watchdog_unregister_governor()

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Tzung-Bi Shih <[email protected]>

[ Upstream commit 7362ba0f9c96ac3ad6a2ca3995bd9fc9a28a8661 ]

When a watchdog governor is unregistered, it updates existing watchdog devices that were using this governor by falling back to default_gov.

If the governor being unregistered is currently set as default_gov, the default_gov is never cleared. This leads to 2 use-after-free issues:
1. New watchdog devices registered after this point will inherit the dangling default_gov.
2. Existing watchdog devices using the unregistered governor will have their wdd->gov reassigned to the dangling default_gov.

Fix the UAF by clearing default_gov if it matches the governor being unregistered.

Fixes da0d12ff2b82 ("watchdog: pretimeout: add panic pretimeout governor")
---
 drivers/watchdog/watchdog_pretimeout.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/watchdog/watchdog_pretimeout.c +2 -0
index 19eb2ed2c7cb0e..02e09b9e396dab 100644
@@ -167,6 +167,8 @@ void watchdog_unregister_governor(struct watchdog_governor *gov)
 	}
 
 	spin_lock_irq(&pretimeout_lock);
+	if (default_gov == gov)
+		default_gov = NULL;
 	list_for_each_entry(p, &pretimeout_list, entry)
 		if (p->wdd->gov == gov)
 			p->wdd->gov = default_gov;
Signature · 1 line
2.53.0
author maintainer
#177 lore raw

PATCH 177/744 watchdog: airoha: Prevent division by zero when clock frequency is zero

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Wayen Yan <[email protected]>

[ Upstream commit bcfcd7619f277842430d197556463b401b839ee9 ]

clk_get_rate() can return 0 when the clock provider is not properly configured or the clock is unmanaged. The driver uses wdt_freq as a divisor directly in airoha_wdt_probe() to compute max_timeout and in airoha_wdt_get_timeleft() to compute the remaining time, which results in a division by zero.

Add a check for wdt_freq == 0 in probe and return -EINVAL with dev_err_probe() to prevent the division by zero and provide a diagnostic message.

Fixes 3cf67f3769b8 ("watchdog: Add support for Airoha EN7851 watchdog")
---
 drivers/watchdog/airoha_wdt.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/watchdog/airoha_wdt.c +3 -0
index dc8ca11c14d81a..4bd333189b87ec 100644
@@ -147,6 +147,9 @@ static int airoha_wdt_probe(struct platform_device *pdev)
 
 	/* Watchdog ticks at half the bus rate */
 	airoha_wdt->wdt_freq = clk_get_rate(bus_clk) / 2;
+	if (!airoha_wdt->wdt_freq)
+		return dev_err_probe(dev, -EINVAL,
+				     "invalid clock frequency\n");
 
 	/* Initialize struct watchdog device */
 	wdog_dev = &airoha_wdt->wdog_dev;
Signature · 1 line
2.53.0
author maintainer
#178 lore raw

PATCH 178/744 wifi: ath10k: fix skb leak on incomplete msdu during rx pop

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Manikanta Pubbisetty <[email protected]>

[ Upstream commit 7393878255e492515858f751ba4c260f248fb108 ]

When ath10k_htt_rx_pop_paddr32_list() or ath10k_htt_rx_pop_paddr64_list() encounters an incomplete frame (RX_ATTENTION_FLAGS_MSDU_DONE not set), it returns -EIO without purging the skb list built up so far, leaking any skbs already queued in the list.

Other early-exit paths within these same functions already call __skb_queue_purge() before returning an error. Add it before the -EIO return as well to be consistent and prevent the leak.

Tested-on: WCN3990 hw1.0 WLAN.HL.3.2.2.c10-00754-QCAHLSWMTPL-1

Fixes c545070e404b ("ath10k: implement rx reorder support")
Fixes 3b0b55b19d1d ("ath10k: Add support for 64 bit HTT in-order indication msg")
---
 drivers/net/wireless/ath/ath10k/htt_rx.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/net/wireless/ath/ath10k/htt_rx.c +2 -0
index 25ab945fecef2c..8f88ea116a32c7 100644
@@ -707,6 +707,7 @@ static int ath10k_htt_rx_pop_paddr32_list(struct ath10k_htt *htt,
 			if (!(__le32_to_cpu(rxd_attention->flags) &
 			      RX_ATTENTION_FLAGS_MSDU_DONE)) {
 				ath10k_warn(htt->ar, "tried to pop an incomplete frame, oops!\n");
+				__skb_queue_purge(list);
 				return -EIO;
 			}
 		}
@@ -771,6 +772,7 @@ static int ath10k_htt_rx_pop_paddr64_list(struct ath10k_htt *htt,
 			if (!(__le32_to_cpu(rxd_attention->flags) &
 			      RX_ATTENTION_FLAGS_MSDU_DONE)) {
 				ath10k_warn(htt->ar, "tried to pop an incomplete frame, oops!\n");
+				__skb_queue_purge(list);
 				return -EIO;
 			}
 		}
Signature · 1 line
2.53.0
author maintainer
#179 lore raw

PATCH 179/744 wifi: ath11k: fix potential buffer underflow in ath11k_hal_rx_msdu_list_get()

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Dmitry Morgun <[email protected]>

[ Upstream commit 7f11e70629650ff6ea140984e5ce188b775b2683 ]

When the first entry in msdu_details has a zero buffer address, the code accesses msdu_details[i - 1] with i == 0, causing a buffer underflow.

Fix similarly to ath12k_wifi7_hal_rx_msdu_list_get() by adding a separate check for i == 0 before the main condition to prevent the out-of-bounds access.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

---
 drivers/net/wireless/ath/ath11k/dp_rx.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/net/wireless/ath/ath11k/dp_rx.c +3 -0
index 2a413e3a07a78c..c9f520c2a93583 100644
@@ -4565,6 +4565,9 @@ static void ath11k_hal_rx_msdu_list_get(struct ath11k *ar,
 	msdu_details = &msdu_link->msdu_link[0];
 
 	for (i = 0; i < HAL_RX_NUM_MSDU_DESC; i++) {
+		if (!i && FIELD_GET(BUFFER_ADDR_INFO0_ADDR,
+				    msdu_details[i].buf_addr_info.info0) == 0)
+			break;
 		if (FIELD_GET(BUFFER_ADDR_INFO0_ADDR,
 			      msdu_details[i].buf_addr_info.info0) == 0) {
 			msdu_desc_info = &msdu_details[i - 1].rx_msdu_info;
Signature · 1 line
2.53.0
author maintainer
#180 lore raw

PATCH 180/744 wifi: ath11k: Flush the posted write after writing to PCIE_SOC_GLOBAL_RESET

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Manivannan Sadhasivam <[email protected]>

[ Upstream commit 0fe8010fc5b147607fc19ba010ba469afc95f35f ]

ath11k_pci_soc_global_reset() tries to reset the device by writing to the PCIE_SOC_GLOBAL_RESET register. But it doesn't do a read-back to ensure that the write gets flushed to the device before the delay.

This may lead to the delay on the host to be insufficient, if the posted write doesn't reach the device before the delay.

So add a read-back after writing to the PCIE_SOC_GLOBAL_RESET register and before the delay.

Compile tested only.

---
 drivers/net/wireless/ath/ath11k/pci.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/net/wireless/ath/ath11k/pci.c +4 -0
index 35bb9e7a63a207..a163168f361764 100644
@@ -199,6 +199,8 @@ static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
 	val |= PCIE_SOC_GLOBAL_RESET_V;
 
 	ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
+	/* Flush the posted write to the device */
+	ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET);
 
 	/* TODO: exact time to sleep is uncertain */
 	delay = 10;
@@ -208,6 +210,8 @@ static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
 
 	ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
+	/* Flush the posted write to the device */
+	ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET);
 
 	mdelay(delay);
 
Signature · 1 line
2.53.0
author maintainer
#181 lore raw

PATCH 181/744 wifi: ath12k: Flush the posted write after writing to PCIE_SOC_GLOBAL_RESET

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Manivannan Sadhasivam <[email protected]>

[ Upstream commit 55f3aa06951cac78b0206bde961c8cf11929a27a ]

ath12k_pci_soc_global_reset() tries to reset the device by writing to the PCIE_SOC_GLOBAL_RESET register. But it doesn't do a read-back to ensure that the write gets flushed to the device before the delay.

This may lead to the delay on the host to be insufficient, if the posted write doesn't reach the device before the delay.

So add a read-back after writing to the PCIE_SOC_GLOBAL_RESET register and before the delay.

Compile tested only.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1

---
 drivers/net/wireless/ath/ath12k/pci.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/net/wireless/ath/ath12k/pci.c +4 -0
index d9a22d6afbb020..fee4129ea4055b 100644
@@ -188,6 +188,8 @@ static void ath12k_pci_soc_global_reset(struct ath12k_base *ab)
 	val |= PCIE_SOC_GLOBAL_RESET_V;
 
 	ath12k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
+	/* Flush the posted write to the device */
+	ath12k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
 
 	/* TODO: exact time to sleep is uncertain */
 	delay = 10;
@@ -197,6 +199,8 @@ static void ath12k_pci_soc_global_reset(struct ath12k_base *ab)
 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
 
 	ath12k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
+	/* Flush the posted write to the device */
+	ath12k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
 
 	mdelay(delay);
 
Signature · 1 line
2.53.0
author maintainer
#182 lore raw

PATCH 182/744 platform/x86/intel/vsec: allocate res with intel_vsec_dev

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Rosen Penev <[email protected]>

[ Upstream commit 8ef6b01cee44803691c0a0c95b36f8ec710e2afb ]

Use a flexible array member to combine allocations. Avoids having to free separately.

Add __counted_by for extra runtime analysis.

Move counting variable assignment to after allocations as is already done by kzalloc_flex for GCC 15 and above.

Stable-dep-of: 09b2ae290a24 ("platform/x86/intel/vsec: free ACPI discovery data on early errors")

---
 drivers/platform/x86/intel/vsec.c      | 14 ++++----------
 drivers/platform/x86/intel/vsec_tpmi.c | 13 ++++---------
 include/linux/intel_vsec.h             |  6 +++---
 3 files changed, 11 insertions(+), 22 deletions(-)
drivers/platform/x86/intel/vsec.c +4 -10
index 439c0c8ac896c7..3ae4557b32b478 100644
@@ -112,7 +112,6 @@ static void intel_vsec_dev_release(struct device *dev)
 	ida_free(intel_vsec_dev->ida, intel_vsec_dev->auxdev.id);
 
 	kfree(intel_vsec_dev->acpi_disc);
-	kfree(intel_vsec_dev->resource);
 	kfree(intel_vsec_dev);
 }
 
@@ -225,7 +224,6 @@ int intel_vsec_add_aux(struct device *parent,
 	ret = xa_alloc(&auxdev_array, &intel_vsec_dev->id, intel_vsec_dev,
 		       PMT_XA_LIMIT, GFP_KERNEL);
 	if (ret < 0) {
-		kfree(intel_vsec_dev->resource);
 		kfree(intel_vsec_dev);
 		return ret;
 	}
@@ -233,7 +231,6 @@ int intel_vsec_add_aux(struct device *parent,
 	id = ida_alloc(intel_vsec_dev->ida, GFP_KERNEL);
 	if (id < 0) {
 		xa_erase(&auxdev_array, intel_vsec_dev->id);
-		kfree(intel_vsec_dev->resource);
 		kfree(intel_vsec_dev);
 		return id;
 	}
@@ -282,7 +279,7 @@ static int intel_vsec_add_dev(struct device *dev, struct intel_vsec_header *head
 			      unsigned long cap_id, u64 base_addr)
 {
 	struct intel_vsec_device __free(kfree) *intel_vsec_dev = NULL;
-	struct resource __free(kfree) *res = NULL;
+	struct resource *res;
 	struct resource *tmp;
 	struct device *parent;
 	unsigned long quirks = info->quirks;
@@ -306,13 +303,12 @@ static int intel_vsec_add_dev(struct device *dev, struct intel_vsec_header *head
 		return -EINVAL;
 	}
 
-	intel_vsec_dev = kzalloc_obj(*intel_vsec_dev);
+	intel_vsec_dev = kzalloc_flex(*intel_vsec_dev, resource, header->num_entries);
 	if (!intel_vsec_dev)
 		return -ENOMEM;
 
-	res = kzalloc_objs(*res, header->num_entries);
-	if (!res)
-		return -ENOMEM;
+	intel_vsec_dev->num_resources = header->num_entries;
+	res = intel_vsec_dev->resource;
 
 	if (quirks & VSEC_QUIRK_TABLE_SHIFT)
 		header->offset >>= TABLE_OFFSET_SHIFT;
@@ -342,8 +338,6 @@ static int intel_vsec_add_dev(struct device *dev, struct intel_vsec_header *head
 	}
 
 	intel_vsec_dev->dev = dev;
-	intel_vsec_dev->resource = no_free_ptr(res);
-	intel_vsec_dev->num_resources = header->num_entries;
 	intel_vsec_dev->quirks = info->quirks;
 	intel_vsec_dev->base_addr = info->base_addr;
 	intel_vsec_dev->priv_data = info->priv_data;
drivers/platform/x86/intel/vsec_tpmi.c +4 -9
index 88f14d0ad4102f..3b76cccb975f6b 100644
@@ -634,15 +634,12 @@ static int tpmi_create_device(struct intel_tpmi_info *tpmi_info,
 	if (!name)
 		return -EOPNOTSUPP;
 
-	res = kzalloc_objs(*res, pfs->pfs_header.num_entries);
-	if (!res)
+	feature_vsec_dev = kzalloc_flex(*feature_vsec_dev, resource, pfs->pfs_header.num_entries);
+	if (!feature_vsec_dev)
 		return -ENOMEM;
 
-	feature_vsec_dev = kzalloc_obj(*feature_vsec_dev);
-	if (!feature_vsec_dev) {
-		kfree(res);
-		return -ENOMEM;
-	}
+	feature_vsec_dev->num_resources = pfs->pfs_header.num_entries;
+	res = feature_vsec_dev->resource;
 
 	snprintf(feature_id_name, sizeof(feature_id_name), "tpmi-%s", name);
 
@@ -655,8 +652,6 @@ static int tpmi_create_device(struct intel_tpmi_info *tpmi_info,
 	}
 
 	feature_vsec_dev->dev = vsec_dev->dev;
-	feature_vsec_dev->resource = res;
-	feature_vsec_dev->num_resources = pfs->pfs_header.num_entries;
 	feature_vsec_dev->priv_data = &tpmi_info->plat_info;
 	feature_vsec_dev->priv_data_size = sizeof(tpmi_info->plat_info);
 	feature_vsec_dev->ida = &intel_vsec_tpmi_ida;
include/linux/intel_vsec.h +3 -3
index 1fe5665a9d02a8..07ea563f524ee2 100644
@@ -135,8 +135,6 @@ struct intel_vsec_platform_info {
  * struct intel_vsec_device - Auxbus specific device information
  * @auxdev:        auxbus device struct for auxbus access
  * @dev:           struct device associated with the device
- * @resource:      PCI discovery resources (BAR windows), one per discovery
- *                 instance. Valid only when @src == INTEL_VSEC_DISC_PCI
  * @acpi_disc:     ACPI discovery tables, each entry is two QWORDs
  *                 in little-endian format as defined by the PMT ACPI spec.
  *                 Valid only when @src == INTEL_VSEC_DISC_ACPI.
@@ -149,11 +147,12 @@ struct intel_vsec_platform_info {
  * @quirks:        specified quirks
  * @base_addr:     base address of entries (if specified)
  * @cap_id:        the enumerated id of the vsec feature
+ * @resource:      PCI discovery resources (BAR windows), one per discovery
+ *                 instance. Valid only when @src == INTEL_VSEC_DISC_PCI
  */
 struct intel_vsec_device {
 	struct auxiliary_device auxdev;
 	struct device *dev;
-	struct resource *resource;
 	u32 (*acpi_disc)[4];
 	enum intel_vsec_disc_source src;
 	struct ida *ida;
@@ -164,6 +163,7 @@ struct intel_vsec_device {
 	unsigned long quirks;
 	u64 base_addr;
 	unsigned long cap_id;
+	struct resource resource[] __counted_by(num_resources);
 };
 
 /**
Signature · 1 line
2.53.0
author maintainer
#183 lore raw

PATCH 183/744 platform/x86/intel/vsec: free ACPI discovery data on early errors

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Yousef Alhouseen <[email protected]>

[ Upstream commit 09b2ae290a241ce1f5f738fb65c35f449dcf663d ]

intel_vsec_add_dev() may attach an ACPI discovery table copy to the intel_vsec_device before passing ownership to intel_vsec_add_aux(). The normal auxiliary-device release path frees that copy, but the earliest intel_vsec_add_aux() failures free only the outer structure directly.

Route those direct frees through a common helper so acpi_disc is released consistently on the parent, xarray, and ID allocation failure paths.

---
 drivers/platform/x86/intel/vsec.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)
drivers/platform/x86/intel/vsec.c +12 -5
index 3ae4557b32b478..5ab2215fdd7fa8 100644
@@ -103,6 +103,12 @@ static void intel_vsec_remove_aux(void *data)
 	auxiliary_device_uninit(data);
 }
 
+static void intel_vsec_dev_free(struct intel_vsec_device *intel_vsec_dev)
+{
+	kfree(intel_vsec_dev->acpi_disc);
+	kfree(intel_vsec_dev);
+}
+
 static void intel_vsec_dev_release(struct device *dev)
 {
 	struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(dev);
@@ -111,8 +117,7 @@ static void intel_vsec_dev_release(struct device *dev)
 
 	ida_free(intel_vsec_dev->ida, intel_vsec_dev->auxdev.id);
 
-	kfree(intel_vsec_dev->acpi_disc);
-	kfree(intel_vsec_dev);
+	intel_vsec_dev_free(intel_vsec_dev);
 }
 
 static const struct vsec_feature_dependency *
@@ -218,20 +223,22 @@ int intel_vsec_add_aux(struct device *parent,
 	struct auxiliary_device *auxdev = &intel_vsec_dev->auxdev;
 	int ret, id;
 
-	if (!parent)
+	if (!parent) {
+		intel_vsec_dev_free(intel_vsec_dev);
 		return -EINVAL;
+	}
 
 	ret = xa_alloc(&auxdev_array, &intel_vsec_dev->id, intel_vsec_dev,
 		       PMT_XA_LIMIT, GFP_KERNEL);
 	if (ret < 0) {
-		kfree(intel_vsec_dev);
+		intel_vsec_dev_free(intel_vsec_dev);
 		return ret;
 	}
 
 	id = ida_alloc(intel_vsec_dev->ida, GFP_KERNEL);
 	if (id < 0) {
 		xa_erase(&auxdev_array, intel_vsec_dev->id);
-		kfree(intel_vsec_dev);
+		intel_vsec_dev_free(intel_vsec_dev);
 		return id;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#184 lore raw

PATCH 184/744 platform/x86: asus-wmi: temporarily revert to setting a charge limit

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Denis Benato <[email protected]>

[ Upstream commit 78bf392ba77dd8b2a25656e489449d2f91cfd1eb ]

A userspace regression has been observed leaving the battery charging threshold unconfigured, so while the fix is being shipped revert the change keeping the infrastructure in place to return to the preferred behaviour as soon as it's appropriate to do.

---
 drivers/platform/x86/asus-wmi.c | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)
drivers/platform/x86/asus-wmi.c +23 -3
index 80144c412b902f..a459b7ad18ba0f 100644
@@ -1566,6 +1566,8 @@ static DEVICE_ATTR_RW(charge_control_end_threshold);
 
 static int asus_wmi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
 {
+	int ret, rv;
+
 	/* The WMI method does not provide a way to specific a battery, so we
 	 * just assume it is the first battery.
 	 * Note: On some newer ASUS laptops (Zenbook UM431DA), the primary/first
@@ -1583,12 +1585,30 @@ static int asus_wmi_battery_add(struct power_supply *battery, struct acpi_batter
 
 	/* The charge threshold is only reset when the system is power cycled,
 	 * and we can't read the current threshold, however the majority of
-	 * platforms retains it, therefore signal the threshold as unknown
-	 * until user explicitly sets it to a new value.
+	 * platforms retains it.
+	 *
+	 * Setting a negative value would signal the threshold as unknown
+	 * until user explicitly sets it to a new value, however to avoid
+	 * regressing userspace, we initialize it to a value of 100.
 	 */
-	charge_end_threshold = -1;
+	charge_end_threshold = 100;
+	ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_RSOC, charge_end_threshold, &rv);
+	if (ret) {
+		pr_err("Failed to reset battery charge threshold\n");
+		goto asus_wmi_battery_add_err;
+	}
+
+	if (rv != 1) {
+		pr_err("Error in battery charge threshold reset\n");
+		ret = -EIO;
+		goto asus_wmi_battery_add_err;
+	}
 
 	return 0;
+asus_wmi_battery_add_err:
+	device_remove_file(&battery->dev,
+			   &dev_attr_charge_control_end_threshold);
+	return ret;
 }
 
 static int asus_wmi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook)
Signature · 1 line
2.53.0
author maintainer
#185 lore raw

PATCH 185/744 firewire: net: Fix fragmented datagram reassembly

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ruoyu Wang <[email protected]>

[ Upstream commit d52a13adbb8ccbab99cd3bad36804e87d8b5c052 ]

fwnet_frag_new() keeps a sorted list of received fragments for a partial datagram. When a new fragment is adjacent to an existing fragment, the code checks whether the new fragment also closes the gap to the next or previous list entry.

Those neighbor lookups currently assume that the current fragment always has a real next or previous fragment. At a list edge, the next or previous entry is the list head, not a struct fwnet_fragment_info.

The gap checks also compare against the old edge of the current fragment instead of the edge after adding the new fragment. As a result, a fragment that bridges two existing ranges may leave two adjacent ranges unmerged, so fwnet_pd_is_complete() can miss a complete datagram.

Check for the list head before looking up the neighboring fragment, and compare the neighbor against the new fragment's far edge when deciding whether to merge all three ranges.

This issue was found by a static analysis checker and confirmed by manual source review.

---
 drivers/firewire/net.c | 39 +++++++++++++++++++++------------------
 1 file changed, 21 insertions(+), 18 deletions(-)
drivers/firewire/net.c +21 -18
index 82b3b6d9ed2df6..2a0727935d7367 100644
@@ -298,31 +298,34 @@ static struct fwnet_fragment_info *fwnet_frag_new(
 		if (fi->offset + fi->len == offset) {
 			/* The new fragment can be tacked on to the end */
 			/* Did the new fragment plug a hole? */
-			fi2 = list_entry(fi->fi_link.next,
-					 struct fwnet_fragment_info, fi_link);
-			if (fi->offset + fi->len == fi2->offset) {
-				/* glue fragments together */
-				fi->len += len + fi2->len;
-				list_del(&fi2->fi_link);
-				kfree(fi2);
-			} else {
-				fi->len += len;
+			if (!list_is_last(&fi->fi_link, &pd->fi_list)) {
+				fi2 = list_next_entry(fi, fi_link);
+				if (offset + len == fi2->offset) {
+					/* glue fragments together */
+					fi->len += len + fi2->len;
+					list_del(&fi2->fi_link);
+					kfree(fi2);
+
+					return fi;
+				}
 			}
+			fi->len += len;
 
 			return fi;
 		}
 		if (offset + len == fi->offset) {
 			/* The new fragment can be tacked on to the beginning */
 			/* Did the new fragment plug a hole? */
-			fi2 = list_entry(fi->fi_link.prev,
-					 struct fwnet_fragment_info, fi_link);
-			if (fi2->offset + fi2->len == fi->offset) {
-				/* glue fragments together */
-				fi2->len += fi->len + len;
-				list_del(&fi->fi_link);
-				kfree(fi);
-
-				return fi2;
+			if (!list_is_first(&fi->fi_link, &pd->fi_list)) {
+				fi2 = list_prev_entry(fi, fi_link);
+				if (fi2->offset + fi2->len == offset) {
+					/* glue fragments together */
+					fi2->len += fi->len + len;
+					list_del(&fi->fi_link);
+					kfree(fi);
+
+					return fi2;
+				}
 			}
 			fi->offset = offset;
 			fi->len += len;
Signature · 1 line
2.53.0
author maintainer
#186 lore raw

PATCH 186/744 wifi: ath12k: Fix low MLO RX throughput on WCN7850

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Yingying Tang <[email protected]>

[ Upstream commit a2fe9dc70f3b8d5716fbcfed5fbfb9cf3948d402 ]

Commit [1] introduced a regression causing severely degraded MLO RX throughput on WCN7850.

On WCN7850, there is only a single ar instance, but MLO uses two link IDs. ath12k_dp_peer->hw_links[] is indexed using ar->hw_link_id, which causes both MLO link IDs to be stored at the same index.

As a result, an incorrect link ID is assigned to MSDUs in ath12k_dp_rx_deliver_msdu(), leading to severe MLO RX throughput loss.

Different chipsets identify the per-MSDU link differently:

- On QCN9274 / IPQ5332, the host owns multiple ar instances and the per-MSDU hw_link_id from the RX descriptor maps cleanly through dp_peer->hw_links[hw_link_id] to the IEEE link_id.

- On single-ar chipsets like WCN7850 / QCC2072, there is only one ar

    instance for both MLO links, so dp_peer->hw_links[] has just one
    valid slot and cannot be used to distinguish the two links. To
    resolve the link, walk dp_peer->link_peers[] and match by
    rxcb->peer_id, which on the link_peer side identifies the link
    peer for the MSDU.

Add a new hw_op set_rx_link_id() so each chipset resolves the link on the RX fast path using whatever signal it actually has, and let the op itself decide whether to populate rx_status::link_valid and rx_status::link_id:

QCN9274 / IPQ5332 : always derive link_id from

                      dp_peer->hw_links[rxcb->hw_link_id] and set
                      link_valid.

WCN7850 / QCC2072 : walk the link_peers[] of dp_peer to find the
link_peer whose peer_id matches rxcb->peer_id, and set link_valid only when a match is found. Otherwise leave link_valid clear so that mac80211 can fall back to its own link resolution path (via addr2 / deflink).

For WCN7850 / QCC2072, walking dp_peer->link_peers[] is bounded by the number of links actually populated, so introduce a link_peers_map bitmap (unsigned long) in struct ath12k_dp_peer that tracks populated slots and use for_each_set_bit() to iterate. Non-MLO clients hit one slot, current MLO clients hit two; the full ATH12K_NUM_MAX_LINKS array is never scanned. The bitmap is maintained with WRITE_ONCE() on the write side (under dp_hw->peer_lock) paired with READ_ONCE() on both the lockless RX read side and the write-side RMW for KCSAN correctness.

Also guard the dp_peer dereference in ath12k_mac_peer_cleanup_all() with a NULL check, since peer->dp_peer can be NULL for self-peers or peers not yet fully assigned, the pre-existing rcu_assign_pointer() call there had the same latent issue.

This restores the correct link ID on WCN7850 without changing the QCN9274 / IPQ5332 data path, which keeps its O(1) hw_links[] indexing.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3

Fixes 11157e0910fd ("wifi: ath12k: Use ath12k_dp_peer in per packet Tx & Rx paths") # [1]
---
 drivers/net/wireless/ath/ath12k/dp_peer.c     |  4 +++
 drivers/net/wireless/ath/ath12k/dp_peer.h     |  1 +
 drivers/net/wireless/ath/ath12k/dp_rx.c       |  7 ++--
 drivers/net/wireless/ath/ath12k/hw.h          | 16 +++++++++
 drivers/net/wireless/ath/ath12k/mac.c         | 10 ++++--
 drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c | 33 +++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wifi7/dp_rx.h |  6 ++++
 drivers/net/wireless/ath/ath12k/wifi7/hw.c    |  3 ++
 8 files changed, 73 insertions(+), 7 deletions(-)
drivers/net/wireless/ath/ath12k/dp_peer.c +4 -0
index a1100782d45e6b..f57f1483c3e47f 100644
@@ -570,6 +570,8 @@ int ath12k_dp_link_peer_assign(struct ath12k_dp *dp, struct ath12k_dp_hw *dp_hw,
 	peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
 
 	rcu_assign_pointer(dp_peer->link_peers[peer->link_id], peer);
+	WRITE_ONCE(dp_peer->link_peers_map,
+		   READ_ONCE(dp_peer->link_peers_map) | BIT(peer->link_id));
 
 	rcu_assign_pointer(dp_hw->dp_peers[peerid_index], dp_peer);
 
@@ -632,6 +634,8 @@ void ath12k_dp_link_peer_unassign(struct ath12k_dp *dp, struct ath12k_dp_hw *dp_
 	peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
 
 	rcu_assign_pointer(dp_peer->link_peers[peer->link_id], NULL);
+	WRITE_ONCE(dp_peer->link_peers_map,
+		   READ_ONCE(dp_peer->link_peers_map) & ~BIT(peer->link_id));
 
 	rcu_assign_pointer(dp_hw->dp_peers[peerid_index], NULL);
 
drivers/net/wireless/ath/ath12k/dp_peer.h +1 -0
index 113b8040010fa3..d4d2ff16e83695 100644
@@ -140,6 +140,7 @@ struct ath12k_dp_peer {
 
 	/* Info used in MMIC verification of * RX fragments */
 	struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
+	unsigned long link_peers_map;
 	struct ath12k_dp_link_peer __rcu *link_peers[ATH12K_NUM_MAX_LINKS];
 	struct ath12k_reoq_buf reoq_bufs[IEEE80211_NUM_TIDS + 1];
 	struct ath12k_dp_rx_tid rx_tid[IEEE80211_NUM_TIDS + 1];
drivers/net/wireless/ath/ath12k/dp_rx.c +3 -4
index b108ccd0f63703..b5dba7c0155f90 100644
@@ -1344,10 +1344,9 @@ void ath12k_dp_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev, struct napi_struc
 
 	pubsta = peer ? peer->sta : NULL;
 
-	if (pubsta && pubsta->valid_links) {
-		status->link_valid = 1;
-		status->link_id = peer->hw_links[rxcb->hw_link_id];
-	}
+	status->link_valid = 0;
+	if (pubsta && pubsta->valid_links)
+		ath12k_hw_set_rx_link_id(dp->hw_params, peer, rxcb, status);
 
 	ath12k_dbg(dp->ab, ATH12K_DBG_DATA,
 		   "rx skb %p len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
drivers/net/wireless/ath/ath12k/hw.h +16 -0
index a9888e0521a1d1..da75d19ae1a007 100644
@@ -13,6 +13,10 @@
 #include "wmi.h"
 #include "hal.h"
 
+struct ath12k_dp_peer;
+struct ath12k_skb_rxcb;
+struct ieee80211_rx_status;
+
 /* Target configuration defines */
 
 /* Num VDEVS per radio */
@@ -224,6 +228,9 @@ struct ath12k_hw_ops {
 	bool (*dp_srng_is_tx_comp_ring)(int ring_num);
 	bool (*is_frame_link_agnostic)(struct ath12k_link_vif *arvif,
 				       struct ieee80211_mgmt *mgmt);
+	void (*set_rx_link_id)(struct ath12k_dp_peer *dp_peer,
+			       struct ath12k_skb_rxcb *rxcb,
+			       struct ieee80211_rx_status *status);
 };
 
 static inline
@@ -254,6 +261,15 @@ static inline int ath12k_hw_mac_id_to_srng_id(const struct ath12k_hw_params *hw,
 	return 0;
 }
 
+static inline void ath12k_hw_set_rx_link_id(const struct ath12k_hw_params *hw,
+					    struct ath12k_dp_peer *dp_peer,
+					    struct ath12k_skb_rxcb *rxcb,
+					    struct ieee80211_rx_status *status)
+{
+	if (hw->hw_ops->set_rx_link_id)
+		hw->hw_ops->set_rx_link_id(dp_peer, rxcb, status);
+}
+
 struct ath12k_fw_ie {
 	__le32 id;
 	__le32 len;
drivers/net/wireless/ath/ath12k/mac.c +7 -3
index 7190aafd3ae693..7408c2577dc2e6 100644
@@ -1234,9 +1234,13 @@ void ath12k_mac_peer_cleanup_all(struct ath12k *ar)
 		/* cleanup dp peer */
 		spin_lock_bh(&dp_hw->peer_lock);
 		dp_peer = peer->dp_peer;
-		peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
-		rcu_assign_pointer(dp_peer->link_peers[peer->link_id], NULL);
-		rcu_assign_pointer(dp_hw->dp_peers[peerid_index], NULL);
+		if (dp_peer) {
+			peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
+			rcu_assign_pointer(dp_peer->link_peers[peer->link_id], NULL);
+			WRITE_ONCE(dp_peer->link_peers_map,
+				   READ_ONCE(dp_peer->link_peers_map) & ~BIT(peer->link_id));
+			rcu_assign_pointer(dp_hw->dp_peers[peerid_index], NULL);
+		}
 		spin_unlock_bh(&dp_hw->peer_lock);
 
 		ath12k_dp_link_peer_rhash_delete(dp, peer);
drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c +33 -0
index a5e290edaa898c..99c56528346940 100644
@@ -5,6 +5,7 @@
  */
 
 #include "dp_rx.h"
+#include "../dp_peer.h"
 #include "../dp_tx.h"
 #include "../peer.h"
 #include "hal_qcn9274.h"
@@ -2242,3 +2243,35 @@ ath12k_wifi7_dp_rxdesc_mpdu_valid(struct ath12k_base *ab,
 
 	return tlv_tag == HAL_RX_MPDU_START;
 }
+
+void
+ath12k_wifi7_dp_rx_set_link_id_qcn9274(struct ath12k_dp_peer *dp_peer,
+				       struct ath12k_skb_rxcb *rxcb,
+				       struct ieee80211_rx_status *status)
+{
+	status->link_valid = 1;
+	status->link_id = dp_peer->hw_links[rxcb->hw_link_id];
+}
+
+void
+ath12k_wifi7_dp_rx_set_link_id_wcn7850(struct ath12k_dp_peer *dp_peer,
+				       struct ath12k_skb_rxcb *rxcb,
+				       struct ieee80211_rx_status *status)
+{
+	struct ath12k_dp_link_peer *link_peer;
+	unsigned long links_map;
+	int i;
+
+	RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
+			 "ath12k set rx link id called without rcu lock");
+
+	links_map = READ_ONCE(dp_peer->link_peers_map);
+	for_each_set_bit(i, &links_map, ATH12K_NUM_MAX_LINKS) {
+		link_peer = rcu_dereference(dp_peer->link_peers[i]);
+		if (link_peer && link_peer->peer_id == rxcb->peer_id) {
+			status->link_valid = 1;
+			status->link_id = link_peer->link_id;
+			return;
+		}
+	}
+}
drivers/net/wireless/ath/ath12k/wifi7/dp_rx.h +6 -0
index 8aa79faf567fd0..1d3a4788a2dd91 100644
@@ -57,4 +57,10 @@ ath12k_wifi7_dp_rxdesc_mpdu_valid(struct ath12k_base *ab,
 				  struct hal_rx_desc *rx_desc);
 int ath12k_wifi7_dp_rx_tid_delete_handler(struct ath12k_base *ab,
 					  struct ath12k_dp_rx_tid_rxq *rx_tid);
+void ath12k_wifi7_dp_rx_set_link_id_qcn9274(struct ath12k_dp_peer *dp_peer,
+					    struct ath12k_skb_rxcb *rxcb,
+					    struct ieee80211_rx_status *status);
+void ath12k_wifi7_dp_rx_set_link_id_wcn7850(struct ath12k_dp_peer *dp_peer,
+					    struct ath12k_skb_rxcb *rxcb,
+					    struct ieee80211_rx_status *status);
 #endif
drivers/net/wireless/ath/ath12k/wifi7/hw.c +3 -0
index cb3185850439ee..f687eb69ea8da4 100644
@@ -158,6 +158,7 @@ static const struct ath12k_hw_ops qcn9274_ops = {
 	.get_ring_selector = ath12k_wifi7_hw_get_ring_selector_qcn9274,
 	.dp_srng_is_tx_comp_ring = ath12k_wifi7_dp_srng_is_comp_ring_qcn9274,
 	.is_frame_link_agnostic = ath12k_wifi7_is_frame_link_agnostic_qcn9274,
+	.set_rx_link_id = ath12k_wifi7_dp_rx_set_link_id_qcn9274,
 };
 
 static const struct ath12k_hw_ops wcn7850_ops = {
@@ -168,6 +169,7 @@ static const struct ath12k_hw_ops wcn7850_ops = {
 	.get_ring_selector = ath12k_wifi7_hw_get_ring_selector_wcn7850,
 	.dp_srng_is_tx_comp_ring = ath12k_wifi7_dp_srng_is_comp_ring_wcn7850,
 	.is_frame_link_agnostic = ath12k_wifi7_is_frame_link_agnostic_wcn7850,
+	.set_rx_link_id = ath12k_wifi7_dp_rx_set_link_id_wcn7850,
 };
 
 static const struct ath12k_hw_ops qcc2072_ops = {
@@ -178,6 +180,7 @@ static const struct ath12k_hw_ops qcc2072_ops = {
 	.get_ring_selector = ath12k_wifi7_hw_get_ring_selector_wcn7850,
 	.dp_srng_is_tx_comp_ring = ath12k_wifi7_dp_srng_is_comp_ring_wcn7850,
 	.is_frame_link_agnostic = ath12k_wifi7_is_frame_link_agnostic_wcn7850,
+	.set_rx_link_id = ath12k_wifi7_dp_rx_set_link_id_wcn7850,
 };
 
 #define ATH12K_TX_RING_MASK_0 0x1
Signature · 1 line
2.53.0
author maintainer
#187 lore raw

PATCH 187/744 wifi: ath6kl: fix OOB read from firmware num_msg in TX complete handler

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Tristan Madani <[email protected]>

[ Upstream commit 3a21c89215cc18f1a97c5e5bfd1da6d4f3d44495 ]

The firmware-controlled num_msg field (u8, 0-255) drives the loop in ath6kl_wmi_tx_complete_event_rx() without validation against the buffer length. This allows out-of-bounds reads of up to 1020 bytes past the WMI event buffer when the firmware sends an inflated num_msg.

Add a check that the buffer is large enough to hold the fixed struct and the num_msg variable-length entries.

---
 drivers/net/wireless/ath/ath6kl/wmi.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)
drivers/net/wireless/ath/ath6kl/wmi.c +12 -0
index 72611a2ceb9d8e..7e65a03be0b7bb 100644
@@ -484,6 +484,18 @@ static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len)
 
 	evt = (struct wmi_tx_complete_event *) datap;
 
+	if (len < sizeof(*evt)) {
+		ath6kl_dbg(ATH6KL_DBG_WMI, "tx complete: invalid len %d\n",
+			   len);
+		return -EINVAL;
+	}
+
+	if (len < sizeof(*evt) + evt->num_msg * sizeof(struct tx_complete_msg_v1)) {
+		ath6kl_dbg(ATH6KL_DBG_WMI, "tx complete: invalid len %d for %u msgs\n",
+			   len, evt->num_msg);
+		return -EINVAL;
+	}
+
 	ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n",
 		   evt->num_msg, evt->msg_len, evt->msg_type);
 
Signature · 1 line
2.53.0
author maintainer
#188 lore raw

PATCH 188/744 wifi: ath6kl: fix OOB read from firmware IE lengths in connect event

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Tristan Madani <[email protected]>

[ Upstream commit 6b47b29730de3232b919d8362749f6814c5f2a33 ]

The firmware-controlled beacon_ie_len, assoc_req_len, and assoc_resp_len fields in ath6kl_wmi_connect_event_rx() are not validated against the buffer length. Their sum (up to 765) can exceed the actual WMI event data, causing out-of-bounds reads during IE parsing and state corruption of wmi->is_wmm_enabled.

Add a check that the total IE length fits within the buffer.

---
 drivers/net/wireless/ath/ath6kl/wmi.c | 8 ++++++++
 1 file changed, 8 insertions(+)
drivers/net/wireless/ath/ath6kl/wmi.c +8 -0
index 7e65a03be0b7bb..2b0c5038ae0403 100644
@@ -874,6 +874,14 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len,
 
 	ev = (struct wmi_connect_event *) datap;
 
+	if (len < sizeof(*ev) + ev->beacon_ie_len +
+	    ev->assoc_req_len + ev->assoc_resp_len) {
+		ath6kl_dbg(ATH6KL_DBG_WMI,
+			   "connect event: IE lengths %u+%u+%u exceed buffer %d\n",
+			   ev->beacon_ie_len, ev->assoc_req_len,
+			   ev->assoc_resp_len, len);
+		return -EINVAL;
+	}
 	if (vif->nw_type == AP_NETWORK) {
 		/* AP mode start/STA connected event */
 		struct net_device *dev = vif->ndev;
Signature · 1 line
2.53.0
author maintainer
#189 lore raw

PATCH 189/744 wifi: carl9170: bound memcpy length in cmd callback to prevent OOB read

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Tristan Madani <[email protected]>

[ Upstream commit 4cde55b2feff9504d1f993ab80e84e7ccb62791c ]

When the firmware sends a command response with a length mismatch, carl9170_cmd_callback() logs the mismatch and calls carl9170_restart() but then falls through to memcpy(ar->readbuf, buffer + 4, len - 4). Since len comes from the firmware and can exceed ar->readlen, this copies more data than the readbuf was allocated for.

Bound the memcpy to min(len - 4, ar->readlen) so that the response is still completed -- avoiding repeated restarts from queued garbage -- while preventing an overread past the response buffer.

---
 drivers/net/wireless/ath/carl9170/rx.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/wireless/ath/carl9170/rx.c +2 -1
index 6833430130f4ca..f6855efc05c0f1 100644
@@ -150,7 +150,8 @@ static void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer)
 	spin_lock(&ar->cmd_lock);
 	if (ar->readbuf) {
 		if (len >= 4)
-			memcpy(ar->readbuf, buffer + 4, len - 4);
+			memcpy(ar->readbuf, buffer + 4,
+			       min_t(u32, len - 4, ar->readlen));
 
 		ar->readbuf = NULL;
 	}
Signature · 1 line
2.53.0
author maintainer
#190 lore raw

PATCH 190/744 wifi: carl9170: fix OOB read from off-by-two in TX status handler

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Tristan Madani <[email protected]>

[ Upstream commit a3f42f1049ad80c65560d2b078ad426c3134f78d ]

The bounds check in carl9170_tx_process_status() uses
i > ((cmd->hdr.len / 2) + 1) which is off by two, allowing 2 extra iterations past valid _tx_status entries when the firmware- controlled hdr.ext exceeds hdr.len/2. Fix by using the correct comparison i >= (cmd->hdr.len / 2).

---
 drivers/net/wireless/ath/carl9170/tx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/ath/carl9170/tx.c +1 -1
index 59caf1e4b15893..06aaf281655b1e 100644
@@ -692,7 +692,7 @@ void carl9170_tx_process_status(struct ar9170 *ar,
 	unsigned int i;
 
 	for (i = 0;  i < cmd->hdr.ext; i++) {
-		if (WARN_ON(i > ((cmd->hdr.len / 2) + 1))) {
+		if (WARN_ON(i >= (cmd->hdr.len / 2))) {
 			print_hex_dump_bytes("UU:", DUMP_PREFIX_NONE,
 					     (void *) cmd, cmd->hdr.len + 4);
 			break;
Signature · 1 line
2.53.0
author maintainer
#191 lore raw

PATCH 191/744 wifi: carl9170: fix buffer overflow in rx_stream failover path

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Tristan Madani <[email protected]>

[ Upstream commit a1a21995c2e1cc2ca6b2226cfe4f5f018370182a ]

The failover continuation in carl9170_rx_stream() copies the full tlen from the second USB transfer instead of capping at rx_failover_missing bytes. When both transfers are near maximum size, the total exceeds the 65535-byte failover SKB, triggering skb_over_panic.

Limit the copy size to the missing byte count.

Fixes a84fab3cbfdc ("carl9170: 802.11 rx/tx processing and usb backend")
[Fix checkpatch CHECK:PARENTHESIS_ALIGNMENT]
---
 drivers/net/wireless/ath/carl9170/rx.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/wireless/ath/carl9170/rx.c +3 -1
index f6855efc05c0f1..0383d5c9698bfa 100644
@@ -918,7 +918,9 @@ static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len)
 				}
 			}
 
-			skb_put_data(ar->rx_failover, tbuf, tlen);
+			skb_put_data(ar->rx_failover, tbuf,
+				     min_t(unsigned int, tlen,
+					   ar->rx_failover_missing));
 			ar->rx_failover_missing -= tlen;
 
 			if (ar->rx_failover_missing <= 0) {
Signature · 1 line
2.53.0
author maintainer
#192 lore raw

PATCH 192/744 btrfs: declare btrfs_ioctl_search_args_v2::buf as __u8

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: You-Kai Zheng <[email protected]>

[ Upstream commit b95181f3929ff98949fa9460ca93eccebbf2d7fc ]

The variable-sized buffer buf in struct btrfs_ioctl_search_args_v2 is declared as __u64[], but it holds a packed byte stream of search results, where all offsets into the buffer are in bytes.

Declaring buf as __u64[] makes it easy for user space to write incorrect pointer arithmetic: adding a byte offset directly to a __u64 pointer scales the offset by 8, landing at byte position offset*8 instead of offset.

This recently caused an infinite loop in btrfs-progs: the accessor read all-zero data from misaddressed items, which fed zeroed search keys back into the ioctl loop and spun forever. The issue was worked around at the time by disabling TREE_SEARCH_V2 entirely in btrfs-progs (d73e69824854:
"btrfs-progs: temporarily disable usage of v2 of search tree ioctl").

The kernel side already treats buf as a byte buffer, so change the declaration to __u8[] to match the actual semantics and prevent similar misuse in user space. The change is ABI compatible: both the structure size and alignment are unchanged.

Fixes cc68a8a5a433 ("btrfs: new ioctl TREE_SEARCH_V2")
---
 include/uapi/linux/btrfs.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/uapi/linux/btrfs.h +1 -1
index 9165154a274d94..16ff7beab9ca59 100644
@@ -598,7 +598,7 @@ struct btrfs_ioctl_search_args_v2 {
 	__u64 buf_size;		   /* in - size of buffer
 					    * out - on EOVERFLOW: needed size
 					    *       to store item */
-	__u64 buf[];                       /* out - found items */
+	__u8 buf[];                        /* out - found items */
 };
 
 /* With a @src_length of zero, the range from @src_offset->EOF is cloned! */
Signature · 1 line
2.53.0
author maintainer
#193 lore raw

PATCH 193/744 btrfs: fix u32 to s64 type conversion in dirty_metadata_bytes accounting

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Dave Chen <[email protected]>

[ Upstream commit 8b5a09ceb61b18b1f0797cd30a549d7dc85d8d50 ]

The percpu_counter dirty_metadata_bytes is updated by negating eb->len and passing it to percpu_counter_add_batch(), whose amount parameter is s64. Since commit 84cda1a6087d ("btrfs: cache folio size and shift in extent_buffer"), eb->len is u32. The u32 result of -eb->len, when widened to the s64 parameter, becomes a large positive value instead of the intended negative value. For eb->len == 16384 the counter adds +4294950912 instead of subtracting 16384.

The counter therefore grows on every metadata writeback instead of shrinking by the extent buffer size, permanently exceeding BTRFS_DIRTY_METADATA_THRESH and causing __btrfs_btree_balance_dirty() to trigger balance_dirty_pages_ratelimited() unconditionally, adding unnecessary writeback pressure.

Cast eb->len to s64 before negation at both call sites so the subtraction is performed in signed 64-bit arithmetic.

Fixes 84cda1a6087d ("btrfs: cache folio size and shift in extent_buffer")
---
 fs/btrfs/extent_io.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
fs/btrfs/extent_io.c +2 -2
index 2275189b786055..f0bfa8a6218a71 100644
@@ -1963,7 +1963,7 @@ static noinline_for_stack bool lock_extent_buffer_for_io(struct extent_buffer *e
 
 		btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
 		percpu_counter_add_batch(&fs_info->dirty_metadata_bytes,
-					 -eb->len,
+					 -(s64)eb->len,
 					 fs_info->dirty_metadata_batch);
 		ret = true;
 	} else {
@@ -3778,7 +3778,7 @@ void btrfs_clear_buffer_dirty(struct btrfs_trans_handle *trans,
 		return;
 
 	buffer_tree_clear_mark(eb, PAGECACHE_TAG_DIRTY);
-	percpu_counter_add_batch(&fs_info->dirty_metadata_bytes, -eb->len,
+	percpu_counter_add_batch(&fs_info->dirty_metadata_bytes, -(s64)eb->len,
 				 fs_info->dirty_metadata_batch);
 
 	for (int i = 0; i < num_extent_folios(eb); i++) {
Signature · 1 line
2.53.0
author maintainer
#194 lore raw

PATCH 194/744 btrfs: dont propagate EXTENT_FLAG_LOGGING to split extent maps

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Leo Martins <[email protected]>

[ Upstream commit 5eff4d5b17fa1950e80bfd1ba43dc0699e61a644 ]

When btrfs_drop_extent_map_range() splits an extent map, the new split maps inherit the original map's flags through a local 'flags' variable. Commit f86f7a75e2fb ("btrfs: use the flags of an extent map to identify the compression type") changed the EXTENT_FLAG_LOGGING clearing to operate on em->flags instead of that local 'flags' copy, so a split of an extent map that is currently being logged wrongly inherits EXTENT_FLAG_LOGGING.

The flag is then never cleared on the split, and when it is freed while still on the inode's modified_extents list (for example by the extent map shrinker) it trips the WARN_ON(!list_empty(&em->list)) in btrfs_free_extent_map() and leads to a use-after-free.

Clear EXTENT_FLAG_LOGGING from the local 'flags' copy used for the splits and only clear EXTENT_FLAG_PINNED from em->flags, restoring the behaviour prior to f86f7a75e2fb.

CC Jeff Layton <[email protected]>
Fixes f86f7a75e2fb ("btrfs: use the flags of an extent map to identify the compression type")
---
 fs/btrfs/extent_map.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
fs/btrfs/extent_map.c +2 -2
index 6b79bff241f21d..a8bce1d4e92c80 100644
@@ -866,13 +866,13 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode, u64 start, u64 end,
 			goto next;
 		}
 
-		flags = em->flags;
 		/*
 		 * In case we split the extent map, we want to preserve the
 		 * EXTENT_FLAG_LOGGING flag on our extent map, but we don't want
 		 * it on the new extent maps.
 		 */
-		em->flags &= ~(EXTENT_FLAG_PINNED | EXTENT_FLAG_LOGGING);
+		flags = em->flags & ~EXTENT_FLAG_LOGGING;
+		em->flags &= ~EXTENT_FLAG_PINNED;
 		modified = !list_empty(&em->list);
 
 		/*
Signature · 1 line
2.53.0
author maintainer
#195 lore raw

PATCH 195/744 btrfs: free mapping node on duplicate reloc root insert

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Guanghui Yang <[email protected]>

[ Upstream commit 6a8269b6459ed870a8156c106a0f597383907872 ]

__add_reloc_root() allocates a mapping_node before inserting it into rc->reloc_root_tree. If rb_simple_insert() finds an existing entry, it returns the existing rb_node and leaves the newly allocated node unlinked.

The error path then returns -EEXIST without freeing the new node. Since the node was never inserted into reloc_root_tree, the later cleanup in put_reloc_control() cannot find it either.

Free the newly allocated node before returning -EEXIST.

The callers currently assert that -EEXIST should not happen, so this is a defensive cleanup for an unexpected duplicate insert path. If the path is ever reached, the local allocation should still be released.

Fixes 57a304cfd43b ("btrfs: do not panic in __add_reloc_root")
---
 fs/btrfs/relocation.c | 1 +
 1 file changed, 1 insertion(+)
fs/btrfs/relocation.c +1 -0
index 6c826be4174934..37dd9c8b352fbc 100644
@@ -497,6 +497,7 @@ static int __add_reloc_root(struct btrfs_root *root)
 		btrfs_err(fs_info,
 			    "Duplicate root found for start=%llu while inserting into relocation tree",
 			    node->bytenr);
+		kfree(node);
 		return -EEXIST;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#196 lore raw

PATCH 196/744 ASoC: tas2781: bound firmware description string parsing

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pengpeng Hou <[email protected]>

[ Upstream commit bc889dfcea9294a1eae7f8e2f3573a90764ae4d0 ]

The TAS2781 firmware parser reads several variable-length description strings with strlen() before checking that the string terminator is present inside the firmware blob. A malformed firmware image without a NUL terminator can therefore make the parser walk past the end of the firmware buffer before the later size checks run.

Add a small bounded string-length helper and use it for all description fields that are parsed from the firmware buffer. Keep the existing size checks for the fixed bytes that follow each string.

---
 sound/soc/codecs/tas2781-fmwlib.c | 63 ++++++++++++++++++++++++++++---
 1 file changed, 57 insertions(+), 6 deletions(-)
sound/soc/codecs/tas2781-fmwlib.c +57 -6
index 885e0b6fed003a..583cda1f77fa24 100644
@@ -12,6 +12,7 @@
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/limits.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
@@ -1099,13 +1100,42 @@ static int tasdevice_load_block_kernel(
 	return 0;
 }
 
+static int tasdevice_fw_strnlen(const struct firmware *fmw, int offset)
+{
+	const u8 *start;
+	const u8 *nul;
+	size_t remaining;
+	size_t len;
+
+	if (offset < 0 || offset >= fmw->size)
+		return -EINVAL;
+
+	start = fmw->data + offset;
+	remaining = fmw->size - offset;
+	nul = memchr(start, '\0', remaining);
+	if (!nul)
+		return -EINVAL;
+
+	len = nul - start;
+	if (len > INT_MAX)
+		return -EOVERFLOW;
+
+	return len;
+}
+
 static int fw_parse_variable_hdr(struct tasdevice_priv
 	*tas_priv, struct tasdevice_dspfw_hdr *fw_hdr,
 	const struct firmware *fmw, int offset)
 {
 	const unsigned char *buf = fmw->data;
-	int len = strlen((char *)&buf[offset]);
+	int len;
 
+	len = tasdevice_fw_strnlen(fmw, offset);
+	if (len < 0) {
+		dev_err(tas_priv->dev, "%s: Description error\n", __func__);
+		offset = len;
+		goto out;
+	}
 	len++;
 
 	if (offset + len + 8 > fmw->size) {
@@ -1237,7 +1267,12 @@ static int fw_parse_data(struct tasdevice_fw *tas_fmw,
 	memcpy(img_data->name, &data[offset], 64);
 	offset += 64;
 
-	n = strlen((char *)&data[offset]);
+	n = tasdevice_fw_strnlen(fmw, offset);
+	if (n < 0) {
+		dev_err(tas_fmw->dev, "%s: Description error\n", __func__);
+		offset = n;
+		goto out;
+	}
 	n++;
 	if (offset + n + 2 > fmw->size) {
 		dev_err(tas_fmw->dev, "%s: Description error\n", __func__);
@@ -1308,7 +1343,12 @@ static int fw_parse_program_data(struct tasdevice_priv *tas_priv,
 		}
 		offset += 64;
 
-		n = strlen((char *)&buf[offset]);
+		n = tasdevice_fw_strnlen(fmw, offset);
+		if (n < 0) {
+			dev_err(tas_priv->dev, "Description err\n");
+			offset = n;
+			goto out;
+		}
 		/* skip '\0' and 5 unused bytes */
 		n += 6;
 		if (offset + n > fmw->size) {
@@ -1371,7 +1411,12 @@ static int fw_parse_configuration_data(
 		memcpy(config->name, &data[offset], 64);
 		offset += 64;
 
-		n = strlen((char *)&data[offset]);
+		n = tasdevice_fw_strnlen(fmw, offset);
+		if (n < 0) {
+			dev_err(tas_priv->dev, "Description err\n");
+			offset = n;
+			goto out;
+		}
 		n += 15;
 		if (offset + n > fmw->size) {
 			dev_err(tas_priv->dev, "Description err\n");
@@ -2133,7 +2178,8 @@ static int fw_parse_calibration_data(struct tasdevice_priv *tas_priv,
 {
 	struct tasdevice_calibration *calibration;
 	unsigned char *data = (unsigned char *)fmw->data;
-	unsigned int i, n;
+	unsigned int i;
+	int n;
 
 	if (offset + 2 > fmw->size) {
 		dev_err(tas_priv->dev, "%s: Calibrations error\n", __func__);
@@ -2165,7 +2211,12 @@ static int fw_parse_calibration_data(struct tasdevice_priv *tas_priv,
 		calibration = &(tas_fmw->calibrations[i]);
 		offset += 64;
 
-		n = strlen((char *)&data[offset]);
+		n = tasdevice_fw_strnlen(fmw, offset);
+		if (n < 0) {
+			dev_err(tas_priv->dev, "Description err\n");
+			offset = n;
+			goto out;
+		}
 		/* skip '\0' and 2 unused bytes */
 		n += 3;
 		if (offset + n > fmw->size) {
Signature · 1 line
2.53.0
author maintainer
#197 lore raw

PATCH 197/744 ASoC: sun4i-codec: Set quirks.playback_only for H616 codec

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Chen-Yu Tsai <[email protected]>

[ Upstream commit d9e96f859de3ea3e99bce927a988449a1816483c ]

The H616 codec does not have capture capabilities. Set the .playback_only quirks flag to denote this.

This was somehow missing from the original driver patch, even though the patch prior to it in the series added this quirk.

Fixes 9155c321a1d0 ("ASoC: sun4i-codec: support allwinner H616 codec")
---
 sound/soc/sunxi/sun4i-codec.c | 1 +
 1 file changed, 1 insertion(+)
sound/soc/sunxi/sun4i-codec.c +1 -0
index f4e22af594fa35..93f511fb61905e 100644
@@ -2237,6 +2237,7 @@ static const struct sun4i_codec_quirks sun50i_h616_codec_quirks = {
 	.reg_dac_fifoc	= REG_FIELD(SUN50I_H616_CODEC_DAC_FIFOC, 0, 31),
 	.reg_dac_txdata	= SUN8I_H3_CODEC_DAC_TXDATA,
 	.has_reset	= true,
+	.playback_only	= true,
 	.dma_max_burst	= SUN4I_DMA_MAX_BURST,
 };
 
Signature · 1 line
2.53.0
author maintainer
#198 lore raw

PATCH 198/744 iommu/amd: Fix IRQ unsafe locking in gdom allocation

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Tycho Andersen (AMD) <[email protected]>

[ Upstream commit 0db3a430d9681fdb29890bef6934cd89cd1745d0 ]

Lockdep complains:

  [  259.410489] =====================================================
  [  259.417287] WARNING: HARDIRQ-safe -> HARDIRQ-unsafe lock order detected
  [  259.424667] 7.0.0-g51db1d8d2113 #54 Not tainted
  [  259.429718] -----------------------------------------------------
  [  259.436516] qemu-system-x86/10143 [HC0[0]:SC0[0]:HE0:SE1] is trying to acquire:
  [  259.444670] ff3b2b1c60305170 (&xa->xa_lock#25){+.+.}-{3:3}, at: __domain_flush_pages+0x17c/0x4b0
  [  259.454485]
                 and this task is already holding:
  [  259.460991] ff3b2b1c98504cc0 (&domain->lock){-.-.}-{3:3}, at: amd_iommu_iotlb_sync+0x25/0x60
  [  259.470408] which would create a new lock dependency:
  [  259.476041]  (&domain->lock){-.-.}-{3:3} -> (&xa->xa_lock#25){+.+.}-{3:3}
  [  259.483615]
                 but this new dependency connects a HARDIRQ-irq-safe lock:
  [  259.492447]  (&domain->lock){-.-.}-{3:3}
  [  259.492449]
                 ... which became HARDIRQ-irq-safe at:
  [  259.503705]   lock_acquire+0xb6/0x2e0
  [  259.507790]   _raw_spin_lock_irqsave+0x3e/0x60
  [  259.512748]   amd_iommu_flush_iotlb_all+0x20/0x50
  [  259.517996]   iommu_dma_free_iova.isra.0+0x1b8/0x1e0
  [  259.523534]   __iommu_dma_unmap+0xc2/0x140
  [  259.528100]   iommu_dma_unmap_phys+0x55/0xc0
  [  259.532863]   dma_unmap_phys+0x274/0x2e0
  [  259.537238]   dma_unmap_page_attrs+0x17/0x30
  [  259.542000]   nvme_unmap_data+0x13e/0x280
  [  259.546473]   nvme_pci_complete_batch+0x45/0x70
  [  259.551524]   nvme_irq+0x83/0x90
  [  259.555123]   __handle_irq_event_percpu+0x92/0x360
  [  259.560466]   handle_irq_event+0x39/0x80
  [  259.564841]   handle_edge_irq+0xb2/0x1a0
  [  259.569214]   __common_interrupt+0x4e/0x130
  [  259.573882]   common_interrupt+0x88/0xa0
  [  259.578256]   asm_common_interrupt+0x27/0x40
  [  259.583019]   cpuidle_enter_state+0x119/0x5d0
  [  259.587877]   cpuidle_enter+0x2e/0x50
  [  259.591962]   do_idle+0x153/0x2c0
  [  259.595657]   cpu_startup_entry+0x29/0x30
  [  259.600128]   start_secondary+0x118/0x150
  [  259.604601]   common_startup_64+0x13e/0x141
  [  259.609266]
                 to a HARDIRQ-irq-unsafe lock:
  [  259.615384]  (&xa->xa_lock#25){+.+.}-{3:3}
  [  259.615386]
                 ... which became HARDIRQ-irq-unsafe at:
  [  259.627039] ...
  [  259.627039]   lock_acquire+0xb6/0x2e0
  [  259.633071]   _raw_spin_lock+0x2f/0x50
  [  259.637250]   amd_iommu_alloc_domain_nested+0x140/0x3c0
  [  259.643078]   iommufd_hwpt_alloc+0x272/0x800 [iommufd]
  [  259.648813]   iommufd_fops_ioctl+0x14e/0x200 [iommufd]
  [  259.654547]   __x64_sys_ioctl+0x9d/0xf0
  ...

Since amd_iommu_domain_flush_pages() necessarily holds domain->lock to do the flush, switch the allocation side in gdom_info_load_or_alloc_locked() to HARDIRQ-safe allocation. The IOMMU_DESTROY->free path has the same issue, so switch that path to HARDIRQ-safe locking as well.

Fixes 757d2b1fdf5b ("iommu/amd: Introduce gDomID-to-hDomID Mapping and handle parent domain invalidation")
---
 drivers/iommu/amd/nested.c | 31 ++++++++++++++++++-------------
 1 file changed, 18 insertions(+), 13 deletions(-)
drivers/iommu/amd/nested.c +18 -13
index 5b902598e68ade..5c9405223f9115 100644
@@ -59,7 +59,9 @@ static int validate_gdte_nested(struct iommu_hwpt_amd_guest *gdte)
 	return 0;
 }
 
-static void *gdom_info_load_or_alloc_locked(struct xarray *xa, unsigned long index)
+static void *gdom_info_load_or_alloc_locked(struct xarray *xa,
+					    unsigned long index,
+					    unsigned long *flags)
 {
 	struct guest_domain_mapping_info *elm, *res;
 
@@ -67,13 +69,13 @@ static void *gdom_info_load_or_alloc_locked(struct xarray *xa, unsigned long ind
 	if (elm)
 		return elm;
 
-	xa_unlock(xa);
+	xa_unlock_irqrestore(xa, *flags);
 	elm = kzalloc_obj(struct guest_domain_mapping_info);
-	xa_lock(xa);
+	xa_lock_irqsave(xa, *flags);
 	if (!elm)
 		return ERR_PTR(-ENOMEM);
 
-	res = __xa_cmpxchg(xa, index, NULL, elm, GFP_KERNEL);
+	res = __xa_cmpxchg(xa, index, NULL, elm, GFP_ATOMIC);
 	if (xa_is_err(res))
 		res = ERR_PTR(xa_err(res));
 
@@ -95,6 +97,7 @@ amd_iommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
 			      const struct iommu_user_data *user_data)
 {
 	int ret;
+	unsigned long irqflags;
 	struct nested_domain *ndom;
 	struct guest_domain_mapping_info *gdom_info;
 	struct amd_iommu_viommu *aviommu = container_of(viommu, struct amd_iommu_viommu, core);
@@ -136,11 +139,12 @@ amd_iommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
 	 * keep track of the gDomID mapping. When the S2 is changed, the INVALIDATE_IOMMU_PAGES
 	 * command must be issued for each hDomID in the xarray.
 	 */
-	xa_lock(&aviommu->gdomid_array);
+	xa_lock_irqsave(&aviommu->gdomid_array, irqflags);
 
-	gdom_info = gdom_info_load_or_alloc_locked(&aviommu->gdomid_array, ndom->gdom_id);
+	gdom_info = gdom_info_load_or_alloc_locked(&aviommu->gdomid_array,
+						   ndom->gdom_id, &irqflags);
 	if (IS_ERR(gdom_info)) {
-		xa_unlock(&aviommu->gdomid_array);
+		xa_unlock_irqrestore(&aviommu->gdomid_array, irqflags);
 		ret = PTR_ERR(gdom_info);
 		goto out_err;
 	}
@@ -148,7 +152,7 @@ amd_iommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
 	/* Check if gDomID exist */
 	if (refcount_inc_not_zero(&gdom_info->users)) {
 		ndom->gdom_info = gdom_info;
-		xa_unlock(&aviommu->gdomid_array);
+		xa_unlock_irqrestore(&aviommu->gdomid_array, irqflags);
 
 		pr_debug("%s: Found gdom_id=%#x, hdom_id=%#x\n",
 			  __func__, ndom->gdom_id, gdom_info->hdom_id);
@@ -161,7 +165,7 @@ amd_iommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
 	if (gdom_info->hdom_id <= 0) {
 		__xa_cmpxchg(&aviommu->gdomid_array,
 			     ndom->gdom_id, gdom_info, NULL, GFP_ATOMIC);
-		xa_unlock(&aviommu->gdomid_array);
+		xa_unlock_irqrestore(&aviommu->gdomid_array, irqflags);
 		ret = -ENOSPC;
 		goto out_err_gdom_info;
 	}
@@ -169,7 +173,7 @@ amd_iommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
 	ndom->gdom_info = gdom_info;
 	refcount_set(&gdom_info->users, 1);
 
-	xa_unlock(&aviommu->gdomid_array);
+	xa_unlock_irqrestore(&aviommu->gdomid_array, irqflags);
 
 	pr_debug("%s: Allocate gdom_id=%#x, hdom_id=%#x\n",
 		 __func__, ndom->gdom_id, gdom_info->hdom_id);
@@ -257,14 +261,15 @@ static int nested_attach_device(struct iommu_domain *dom, struct device *dev,
 
 static void nested_domain_free(struct iommu_domain *dom)
 {
+	unsigned long irqflags;
 	struct guest_domain_mapping_info *curr;
 	struct nested_domain *ndom = to_ndomain(dom);
 	struct amd_iommu_viommu *aviommu = ndom->viommu;
 
-	xa_lock(&aviommu->gdomid_array);
+	xa_lock_irqsave(&aviommu->gdomid_array, irqflags);
 
 	if (!refcount_dec_and_test(&ndom->gdom_info->users)) {
-		xa_unlock(&aviommu->gdomid_array);
+		xa_unlock_irqrestore(&aviommu->gdomid_array, irqflags);
 		return;
 	}
 
@@ -275,7 +280,7 @@ static void nested_domain_free(struct iommu_domain *dom)
 	curr = __xa_cmpxchg(&aviommu->gdomid_array, ndom->gdom_id,
 			    ndom->gdom_info, NULL, GFP_ATOMIC);
 
-	xa_unlock(&aviommu->gdomid_array);
+	xa_unlock_irqrestore(&aviommu->gdomid_array, irqflags);
 	if (WARN_ON(!curr || xa_err(curr)))
 		return;
 
Signature · 1 line
2.53.0
author maintainer
#199 lore raw

PATCH 199/744 iommu/amd: Fix nested domain leak

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Tycho Andersen (AMD) <[email protected]>

[ Upstream commit 283c5c4c34b4c8d1ebd038d8f360c5ba7fcc767b ]

A couple of runs of different AI tools have generated something like the following bug report:

In nested_domain_free(), when refcount_dec_and_test() returns false (other nested domains still reference the same gdom_info), the function returns without calling kfree(ndom), leaking the nested_domain structure. This problem wasn't introduced by this patch, but exists in the code from commit 757d2b1fdf5b that the patch modifies. Each nested_domain (ndom) is allocated individually in amd_iommu_alloc_domain_nested() via kzalloc_obj(*ndom). The .free callback is the sole point responsible for freeing this domain. When the refcount is > 0, only the xa_unlock_irqrestore is performed and the function returns, leaving ndom permanently allocated. This leak occurs every time a nested domain sharing a gDomID is destroyed while other domains still use that gDomID.

There is a similar leak later in this function in the WARN_ON() test when the mapping is already NULL. Switch to a RAII-based cleanup for ndom, since it should always be freed in this function.

Fixes 757d2b1fdf5b ("iommu/amd: Introduce gDomID-to-hDomID Mapping and handle parent domain invalidation")
---
 drivers/iommu/amd/nested.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/iommu/amd/nested.c +1 -2
index 5c9405223f9115..63b53b29e02989 100644
@@ -263,7 +263,7 @@ static void nested_domain_free(struct iommu_domain *dom)
 {
 	unsigned long irqflags;
 	struct guest_domain_mapping_info *curr;
-	struct nested_domain *ndom = to_ndomain(dom);
+	struct nested_domain *ndom __free(kfree) = to_ndomain(dom);
 	struct amd_iommu_viommu *aviommu = ndom->viommu;
 
 	xa_lock_irqsave(&aviommu->gdomid_array, irqflags);
@@ -290,7 +290,6 @@ static void nested_domain_free(struct iommu_domain *dom)
 
 	amd_iommu_pdom_id_free(ndom->gdom_info->hdom_id);
 	kfree(curr);
-	kfree(ndom);
 }
 
 static const struct iommu_domain_ops nested_domain_ops = {
Signature · 1 line
2.53.0
author maintainer
#200 lore raw

PATCH 200/744 ALSA: hda: cs35l41: validate and free ACPI mute object

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Guangshuo Li <[email protected]>

[ Upstream commit 3b597d24dc0455ae926f1053f97c2725038fc3cd ]

cs35l41_get_acpi_mute_state() evaluates a _DSM method to get the ACPI mute state and reads the first byte from the returned object.

However, the returned ACPI object is owned by the caller and is never freed after use, so each successful query leaks the _DSM result object.

The code also assumes that the returned object is a buffer with at least one byte. A malformed firmware response can return a different object type or an empty buffer, and the direct ret->buffer.pointer dereference can then access an invalid pointer.

Use the typed _DSM helper, validate that the returned buffer contains at least one byte, and free the ACPI object after reading it.

Fixes 447106e92a0c ("ALSA: hda: cs35l41: Support mute notifications for CS35L41 HDA")
---
 sound/hda/codecs/side-codecs/cs35l41_hda.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
sound/hda/codecs/side-codecs/cs35l41_hda.c +10 -1
index 64a5bd895fd1e6..237059ef22f5c7 100644
@@ -1434,10 +1434,19 @@ static int cs35l41_get_acpi_mute_state(struct cs35l41_hda *cs35l41, acpi_handle
 	guid_parse(CS35L41_UUID, &guid);
 
 	if (cs35l41_dsm_supported(handle, CS35L41_DSM_GET_MUTE)) {
-		ret = acpi_evaluate_dsm(handle, &guid, 0, CS35L41_DSM_GET_MUTE, NULL);
+		ret = acpi_evaluate_dsm_typed(handle, &guid, 0,
+			      CS35L41_DSM_GET_MUTE, NULL,
+			      ACPI_TYPE_BUFFER);
+
 		if (!ret)
 			return -EINVAL;
+		if (!ret->buffer.length || !ret->buffer.pointer) {
+			ACPI_FREE(ret);
+			return -EINVAL;
+		}
+
 		mute = *ret->buffer.pointer;
+		ACPI_FREE(ret);
 		dev_dbg(cs35l41->dev, "CS35L41_DSM_GET_MUTE: %d\n", mute);
 	}
 
Signature · 1 line
2.53.0
author maintainer
#201 lore raw

PATCH 201/744 ASoC: bt-sco: fix duplicate DAPM widget names for wideband DAI

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Shengjiu Wang <[email protected]>

[ Upstream commit 0b604e886ece11b71c4daaeccc512c784b89b014 ]

The bt-sco-pcm-wb DAI uses the same stream_name strings as bt-sco-pcm ("Playback" and "Capture"). This causes duplicate DAPM AIF widget names within the same component, leading to debugfs warnings:

debugfs: 'Playback' already exists in 'dapm'
debugfs: 'Capture' already exists in 'dapm'

Give the wideband DAI distinct stream names ("WB Playback" and "WB Capture") and add corresponding DAPM AIF widgets and routes for them.

Fixes 5947e1b4992e ("ASoC: bt-sco: extend rate and add a general compatible string")
Assisted-by VeroCoder:claude-sonnet-4-5
---
 sound/soc/codecs/bt-sco.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
sound/soc/codecs/bt-sco.c +8 -2
index 3afcef2dfa3529..c0bf45b76cb8c5 100644
@@ -17,11 +17,17 @@ static const struct snd_soc_dapm_widget bt_sco_widgets[] = {
 			    SND_SOC_NOPM, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("BT_SCO_TX", "Capture", 0,
 			     SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("BT_SCO_RX_WB", "WB Playback", 0,
+			    SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("BT_SCO_TX_WB", "WB Capture", 0,
+			     SND_SOC_NOPM, 0, 0),
 };
 
 static const struct snd_soc_dapm_route bt_sco_routes[] = {
 	{ "BT_SCO_TX", NULL, "RX" },
 	{ "TX", NULL, "BT_SCO_RX" },
+	{ "BT_SCO_TX_WB", NULL, "RX" },
+	{ "TX", NULL, "BT_SCO_RX_WB" },
 };
 
 static struct snd_soc_dai_driver bt_sco_dai[] = {
@@ -45,14 +51,14 @@ static struct snd_soc_dai_driver bt_sco_dai[] = {
 	{
 		.name = "bt-sco-pcm-wb",
 		.playback = {
-			.stream_name = "Playback",
+			.stream_name = "WB Playback",
 			.channels_min = 1,
 			.channels_max = 1,
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		},
 		.capture = {
-			 .stream_name = "Capture",
+			 .stream_name = "WB Capture",
 			.channels_min = 1,
 			.channels_max = 1,
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
Signature · 1 line
2.53.0
author maintainer
#202 lore raw

PATCH 202/744 arm_mpam: Fix software reset values of MPAMCFG_PRI

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ben Horgan <[email protected]>

[ Upstream commit 9469764292e0d6825c9bf51d75682e3a623b9b6b ]

Priority partitioning is not supported other than to set the per-PARTID defaults in MPAMCFG_PRI, INTPRI and DSPRI, to the highest priority. When 0 is the lowest priority, all ones is the highest priority. However, these values are calculated with an extra higher bit set.

Luckily, there is still no chance of setting functional bits incorrectly. When the priority widths are maximal, this is ensured as the fields have width 16 and a u16 holds the value for each field. When the widths are smaller, the higher order bits beyond the advertised widths, MPAMF_PRI_IDR.DSPRI_WD and MPAMF_PRI_IDR.INTPRI_WD, in the priority fields INTPRI and DSPRI are not used to calculate the priority. It is not specified whether these higher order bits are RAZ/WI or Res0 and so it is desirable not to set them to avoid the chance of misleading reads.

Correct the priority reset values.

Fixes 880df85d8673 ("arm_mpam: Probe and reset the rest of the features")
---
 drivers/resctrl/mpam_devices.c | 26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)
drivers/resctrl/mpam_devices.c +16 -10
index 988fc291241d23..54e9da3158a89d 100644
@@ -1535,12 +1535,9 @@ static u16 mpam_wa_t241_calc_min_from_max(struct mpam_props *props,
 static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
 				      struct mpam_config *cfg)
 {
-	u32 pri_val = 0;
 	u16 cmax = MPAMCFG_CMAX_CMAX;
 	struct mpam_msc *msc = ris->vmsc->msc;
 	struct mpam_props *rprops = &ris->props;
-	u16 dspri = GENMASK(rprops->dspri_wd, 0);
-	u16 intpri = GENMASK(rprops->intpri_wd, 0);
 
 	mutex_lock(&msc->part_sel_lock);
 	__mpam_part_sel(ris->ris_idx, partid, msc);
@@ -1605,16 +1602,25 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
 
 	if (mpam_has_feature(mpam_feat_intpri_part, rprops) ||
 	    mpam_has_feature(mpam_feat_dspri_part, rprops)) {
-		/* aces high? */
-		if (!mpam_has_feature(mpam_feat_intpri_part_0_low, rprops))
-			intpri = 0;
-		if (!mpam_has_feature(mpam_feat_dspri_part_0_low, rprops))
-			dspri = 0;
+		u32 pri_val = 0;
+
+		if (mpam_has_feature(mpam_feat_intpri_part, rprops)) {
+			u16 intpri = GENMASK(rprops->intpri_wd - 1, 0);
+
+			/* aces high? */
+			if (!mpam_has_feature(mpam_feat_intpri_part_0_low, rprops))
+				intpri = 0;
 
-		if (mpam_has_feature(mpam_feat_intpri_part, rprops))
 			pri_val |= FIELD_PREP(MPAMCFG_PRI_INTPRI, intpri);
-		if (mpam_has_feature(mpam_feat_dspri_part, rprops))
+		}
+		if (mpam_has_feature(mpam_feat_dspri_part, rprops)) {
+			u16 dspri = GENMASK(rprops->dspri_wd - 1, 0);
+
+			if (!mpam_has_feature(mpam_feat_dspri_part_0_low, rprops))
+				dspri = 0;
+
 			pri_val |= FIELD_PREP(MPAMCFG_PRI_DSPRI, dspri);
+		}
 
 		mpam_write_partsel_reg(msc, PRI, pri_val);
 	}
Signature · 1 line
2.53.0
author maintainer
#203 lore raw

PATCH 203/744 arm_mpam: Fix MPAMCFG_MBW_PBM register setting

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Fenghua Yu <[email protected]>

[ Upstream commit 021118ce5ea954ec316d7e30bcf4506e12eb5222 ]

MPAMCFG_MBW_PBM is written from cfg if cfg has the MBW partition feature. It is reset when cfg does not have the MBW partition feature.

But the register handling is reversed. This may cause an incorrect register setting. For example, during an MPAM reset, reset_cfg is empty (no MBW partition feature set), and cfg->mbw_pbm is 0. Instead of resetting MPAMCFG_MBW_PBM to all 1's, the current logic will set it to cfg->mbw_pbm, which is 0.

Fix the issue by swapping the if/else branches.

Fixes a1cb6577f575 ("arm_mpam: Reset when feature configuration bit unset")
---
 drivers/resctrl/mpam_devices.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/resctrl/mpam_devices.c +2 -2
index 54e9da3158a89d..18ae935e8d51a5 100644
@@ -1563,9 +1563,9 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
 
 	if (mpam_has_feature(mpam_feat_mbw_part, rprops)) {
 		if (mpam_has_feature(mpam_feat_mbw_part, cfg))
-			mpam_reset_msc_bitmap(msc, MPAMCFG_MBW_PBM, rprops->mbw_pbm_bits);
-		else
 			mpam_write_partsel_reg(msc, MBW_PBM, cfg->mbw_pbm);
+		else
+			mpam_reset_msc_bitmap(msc, MPAMCFG_MBW_PBM, rprops->mbw_pbm_bits);
 	}
 
 	if (mpam_has_feature(mpam_feat_mbw_min, rprops)) {
Signature · 1 line
2.53.0
author maintainer
#204 lore raw

PATCH 204/744 arm_mpam: guard MBWU state before adding it to garbage

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Guangshuo Li <[email protected]>

[ Upstream commit 977f52909c624210178a1247fab0b02b110c1106 ]

__destroy_component_cfg() adds each RIS mbwu_state object to the MPAM garbage list when destroying component configuration.

However, mbwu_state is allocated per RIS and only for RISes with MBWU monitors. A component can therefore have comp->cfg allocated while some RISes still have ris->mbwu_state set to NULL.

Passing a NULL mbwu_state to add_to_garbage() dereferences the NULL pointer inside the macro.

Skip RISes that do not have an mbwu_state object before adding them to the garbage list.

Fixes 41e8a14950e1 ("arm_mpam: Track bandwidth counter state for power management")
---
 drivers/resctrl/mpam_devices.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/resctrl/mpam_devices.c +4 -2
index 18ae935e8d51a5..43dfce57fae1c1 100644
@@ -2595,8 +2595,10 @@ static void __destroy_component_cfg(struct mpam_component *comp)
 		msc = vmsc->msc;
 
 		if (mpam_mon_sel_lock(msc)) {
-			list_for_each_entry(ris, &vmsc->ris, vmsc_list)
-				add_to_garbage(ris->mbwu_state);
+			list_for_each_entry(ris, &vmsc->ris, vmsc_list) {
+				if (ris->mbwu_state)
+					add_to_garbage(ris->mbwu_state);
+			}
 			mpam_mon_sel_unlock(msc);
 		}
 	}
Signature · 1 line
2.53.0
author maintainer
#205 lore raw

PATCH 205/744 ASoC: cs35l56: Fix potential probe() deadlock

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Richard Fitzgerald <[email protected]>

[ Upstream commit 93c2a8ea2454b7b14eb378a58cad8a83c0ffc903 ]

On I2C/SPI call cs35l56_init() before calling snd_soc_register_component() to prevent the potential for a deadlock on init_completion.

For most buses all the hardware would be ready when probe() returns, but on SoundWire, probe() must return before the SoundWire bus driver will enumerate the device. All access to the registers must be deferred until the driver receives an ATTACHED notification. But anything that could return -EPROBE_DEFER must be called during probe, and that includes snd_soc_register_component(). Because of that, on SoundWire the ASoC component can be created before the registers are accssible, so cs35l56_component_probe() waits for init_completion to signal that the registers are accessible.

On I2C/SPI this 2-stage startup isn't required so their probe() functions simply called cs35l56_common_probe() and then cs35l56_init(). The problem with this was that snd_soc_register_component() was still called early. If this triggered ASoC to create the card, ASoC would call cs35l56_component_probe() which waits on init_completion - but this would be running inside the cs35l56 driver probe() so blocking it from reaching the code that signals init_completion, causing a deadlock.

---
 sound/soc/codecs/cs35l56-i2c.c |  4 +---
 sound/soc/codecs/cs35l56-spi.c |  4 +---
 sound/soc/codecs/cs35l56.c     | 15 +++++++++++++++
 3 files changed, 17 insertions(+), 6 deletions(-)
sound/soc/codecs/cs35l56-i2c.c +1 -3
index 0492ddc4102d80..8259714d8b2692 100644
@@ -55,9 +55,7 @@ static int cs35l56_i2c_probe(struct i2c_client *client)
 	if (ret != 0)
 		return ret;
 
-	ret = cs35l56_init(cs35l56);
-	if (ret == 0)
-		ret = cs35l56_irq_request(&cs35l56->base, client->irq);
+	ret = cs35l56_irq_request(&cs35l56->base, client->irq);
 	if (ret < 0)
 		cs35l56_remove(cs35l56);
 
sound/soc/codecs/cs35l56-spi.c +1 -3
index 9bc9b7c98390dc..b1eb924a5b6ccf 100644
@@ -44,9 +44,7 @@ static int cs35l56_spi_probe(struct spi_device *spi)
 	if (ret != 0)
 		return ret;
 
-	ret = cs35l56_init(cs35l56);
-	if (ret == 0)
-		ret = cs35l56_irq_request(&cs35l56->base, spi->irq);
+	ret = cs35l56_irq_request(&cs35l56->base, spi->irq);
 	if (ret < 0)
 		cs35l56_remove(cs35l56);
 
sound/soc/codecs/cs35l56.c +15 -0
index 033028a4734b50..001985e07d57c9 100644
@@ -1975,6 +1975,16 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
 		goto err;
 	}
 
+	/*
+	 * On SoundWire the cs35l56_init() cannot be run until after the
+	 * device has been enumerated by the SoundWire core.
+	 */
+	if (!cs35l56->sdw_peripheral) {
+		ret = cs35l56_init(cs35l56);
+		if (ret)
+			goto err_remove_wm_adsp;
+	}
+
 	ret = snd_soc_register_component(cs35l56->base.dev,
 					 &soc_component_dev_cs35l56,
 					 cs35l56_dai, ARRAY_SIZE(cs35l56_dai));
@@ -1989,6 +1999,11 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
 	wm_adsp2_remove(&cs35l56->dsp);
 
 err:
+	if (pm_runtime_enabled(cs35l56->base.dev)) {
+		pm_runtime_dont_use_autosuspend(cs35l56->base.dev);
+		pm_runtime_disable(cs35l56->base.dev);
+	}
+
 	gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
 	regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies);
 
Signature · 1 line
2.53.0
author maintainer
#206 lore raw

PATCH 206/744 ASoC: cs35l56: Use complete_all() to signal init_completion

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Richard Fitzgerald <[email protected]>

[ Upstream commit e0bffb63a2eda0af82ed7e6357ac67c2db990c21 ]

In cs35l56_init() use complete_all() to signal init_completion instead of complete().

cs35l56_init() was signaling init_completion using the complete() function. This only releases ONE waiter.

If cs35l56_component_probe() was called multiple times the first time would consume that one signal, then future calls would timeout waiting for the completion. This could happen if:

- The component is probed, removed, then probed again without the cs35l56 module being removed.

- A call to component_probe() returns an error and ASoC calls it again later.

It should use complete_all() so that after it has been signaled it will allow any code that waits on it to continue immediately.

The one case where the driver must wait for initialization to run again is when waiting for a reboot after firmware download, and here the code correctly calls reinit_completion() first.

Fixes e496112529006 ("ASoC: cs35l56: Add driver for Cirrus Logic CS35L56")
---
 sound/soc/codecs/cs35l56.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/cs35l56.c +1 -1
index 001985e07d57c9..ad0f88cc0fb4b6 100644
@@ -2089,7 +2089,7 @@ int cs35l56_init(struct cs35l56_private *cs35l56)
 		return dev_err_probe(cs35l56->base.dev, ret, "Failed to write ASP1_CONTROL3\n");
 
 	cs35l56->base.init_done = true;
-	complete(&cs35l56->init_completion);
+	complete_all(&cs35l56->init_completion);
 
 	return 0;
 }
Signature · 1 line
2.53.0
author maintainer
#207 lore raw

PATCH 207/744 wifi: iwlwifi: mvm: validate SAR GEO response payload size

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pagadala Yesu Anjaneyulu <[email protected]>

[ Upstream commit 408d7da38272ce48e2db79b8a9895999f94d7655 ]

The SAR GEO command response is cast to iwl_geo_tx_power_profiles_resp without verifying the payload length. A malformed or unexpected firmware response can lead to reading an invalid structure layout.

Add an explicit size check before accessing the response data and return -EIO when the payload size is wrong.

---
 drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
drivers/net/wireless/intel/iwlwifi/mvm/fw.c +10 -0
index 6e507d6dcdd2a1..fa523be91d8ad3 100644
@@ -964,12 +964,22 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
 		return ret;
 	}
 
+	if (IWL_FW_CHECK(mvm,
+			 iwl_rx_packet_payload_len(cmd.resp_pkt) !=
+			 sizeof(*resp),
+			 "Wrong size for iwl_geo_tx_power_profiles_resp: %d\n",
+			 iwl_rx_packet_payload_len(cmd.resp_pkt))) {
+		ret = -EIO;
+		goto out;
+	}
+
 	resp = (void *)cmd.resp_pkt->data;
 	ret = le32_to_cpu(resp->profile_idx);
 
 	if (WARN_ON(ret > BIOS_GEO_MAX_PROFILE_NUM))
 		ret = -EIO;
 
+out:
 	iwl_free_resp(&cmd);
 	return ret;
 }
Signature · 1 line
2.53.0
author maintainer
#208 lore raw

PATCH 208/744 wifi: iwlwifi: fix pointer arithmetic in iwl_add_mcc_to_tas_block_list

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Emmanuel Grumbach <[email protected]>

[ Upstream commit bc796f84ec9a95b356959ec7caf1d4fce33f3a76 ]

The expression list[*size++] increments the pointer 'size' rather than the u8 value it points to (operator precedence: ++ binds to the pointer before the dereference). As a result the block-list entry is written at the correct index but *size is never incremented, so the caller's count stays at zero and subsequent calls overwrite slot 0 every time.

Change to list[(*size)++] so that the value pointed to by size is incremented after use as the array index.

Fixes 5f4656610edb ("wifi: iwlwifi: extend TAS_CONFIG cmd support for v5")
Assisted-by GitHubCopilot:gpt-5.3-codex
---
 drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +1 -1
index 55128caac7ed9f..14c813cf530f66 100644
@@ -384,7 +384,7 @@ bool iwl_add_mcc_to_tas_block_list(u16 *list, u8 *size, u16 mcc)
 	if (*size >= IWL_WTAS_BLACK_LIST_MAX)
 		return false;
 
-	list[*size++] = mcc;
+	list[(*size)++] = mcc;
 	return true;
 }
 IWL_EXPORT_SYMBOL(iwl_add_mcc_to_tas_block_list);
Signature · 1 line
2.53.0
author maintainer
#209 lore raw

PATCH 209/744 wifi: iwlwifi: validate payload length in iwl_pnvm_complete_fn

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Emmanuel Grumbach <[email protected]>

[ Upstream commit daec24a5ed5da77a108e246ad77aa8b889911f93 ]

iwl_pnvm_complete_fn() casts pkt->data directly to struct iwl_pnvm_init_complete_ntfy and reads the status field without first verifying that the firmware notification payload is large enough to contain that structure.

Add a WARN_ON_ONCE check against sizeof(*pnvm_ntf) and return early without reading uninitialised memory if the payload is too short.

Fixes b3e4c0f34c17 ("iwlwifi: move PNVM implementation to common code")
Assisted-by GitHubCopilot:gpt-5.3-codex
---
 drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +8 -1
index afff8d51ca950c..ec0ff58ab312d5 100644
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright(c) 2020-2025 Intel Corporation
+ * Copyright(c) 2020-2026 Intel Corporation
  */
 
 #include "iwl-drv.h"
@@ -12,6 +12,7 @@
 #include "fw/api/alive.h"
 #include "fw/uefi.h"
 #include "fw/img.h"
+#include "fw/dbg.h"
 
 #define IWL_PNVM_REDUCED_CAP_BIT BIT(25)
 
@@ -26,6 +27,12 @@ static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data *notif_wait,
 	struct iwl_trans *trans = (struct iwl_trans *)data;
 	struct iwl_pnvm_init_complete_ntfy *pnvm_ntf = (void *)pkt->data;
 
+	if (IWL_FW_CHECK(trans,
+			 iwl_rx_packet_payload_len(pkt) < sizeof(*pnvm_ntf),
+			 "Bad notif len: %d\n",
+			 iwl_rx_packet_payload_len(pkt)))
+		return true;
+
 	IWL_DEBUG_FW(trans,
 		     "PNVM complete notification received with status 0x%0x\n",
 		     le32_to_cpu(pnvm_ntf->status));
Signature · 1 line
2.53.0
author maintainer
#210 lore raw

PATCH 210/744 wifi: iwlwifi: mvm: fix read in wake packet notification handler

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Shahar Tzarfati <[email protected]>

[ Upstream commit 9d7657aae8c1579584c67b0b66114a6a98db8b2f ]

In iwl_mvm_wowlan_store_wake_pkt(), packet_len was initialized from notif->wake_packet_length before the explicit check that len >= sizeof(*notif).

Move the assignment of packet_len to after the size check so that notif->wake_packet_length is only accessed once the payload length has been validated.

---
 drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/wireless/intel/iwlwifi/mvm/d3.c +2 -1
index 9a74f60c91850f..72d7403de04d82 100644
@@ -2756,7 +2756,7 @@ static int iwl_mvm_wowlan_store_wake_pkt(struct iwl_mvm *mvm,
 					 struct iwl_wowlan_status_data *status,
 					 u32 len)
 {
-	u32 data_size, packet_len = le32_to_cpu(notif->wake_packet_length);
+	u32 data_size, packet_len;
 
 	if (len < sizeof(*notif)) {
 		IWL_ERR(mvm, "Invalid WoWLAN wake packet notification!\n");
@@ -2775,6 +2775,7 @@ static int iwl_mvm_wowlan_store_wake_pkt(struct iwl_mvm *mvm,
 		return -EIO;
 	}
 
+	packet_len = le32_to_cpu(notif->wake_packet_length);
 	data_size = len - offsetof(struct iwl_wowlan_wake_pkt_notif, wake_packet);
 
 	/* data_size got the padding from the notification, remove it. */
Signature · 1 line
2.53.0
author maintainer
#211 lore raw

PATCH 211/744 usb: atm: ueagle-atm: reject descriptors that confuse probe and disconnect

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Diego Fernando Mancera Gomez <[email protected]>

[ Upstream commit 71132cedd1ecbc4032d76e9928c18a10f7e39b80 ]

uea_probe() distinguishes a pre-firmware device from a post-firmware one using the USB id (UEA_IS_PREFIRM()), and stores a different object as the interface data in each case: a 'struct completion' for a pre-firmware device (to be waited on in .disconnect()), or a 'struct usbatm_data' for a post-firmware one.

uea_disconnect() instead tells the two apart by the number of interfaces of the active configuration (a pre-firmware device exposes a single interface, ADI930 has 2 and eagle has 3), and casts the interface data accordingly.

Because the two handlers use different criteria, a crafted device that advertises a pre-firmware id together with a multi-interface descriptor (or a post-firmware id with a single interface) makes them disagree: the small 'struct completion' stored by uea_probe() is then passed to usbatm_usb_disconnect(), which casts it to 'struct usbatm_data' and takes instance->serialize, reading past the end of the allocation:

  BUG: KASAN: slab-out-of-bounds in __mutex_lock+0x152a/0x1b80
  Read of size 8 at addr ffff8880470e2c60 by task kworker/1:2/982
  ...
   __mutex_lock+0x152a/0x1b80
   usbatm_usb_disconnect+0x70/0x820
   uea_disconnect+0x133/0x2c0
   usb_unbind_interface+0x1dd/0x9e0
  ...
  which belongs to the cache kmalloc-96 of size 96
  The buggy address is located 0 bytes to the right of
   allocated 96-byte region [ffff8880470e2c00, ffff8880470e2c60)

Reject such inconsistent descriptors in uea_probe() so that both handlers always make the same pre/post-firmware decision.

---
 drivers/usb/atm/ueagle-atm.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
drivers/usb/atm/ueagle-atm.c +17 -0
index 1e12fc19f8726d..ee77c38f4ed145 100644
@@ -2551,6 +2551,7 @@ static struct usbatm_driver uea_usbatm_driver = {
 static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
 	struct usb_device *usb = interface_to_usbdev(intf);
+	bool single_iface = usb->config->desc.bNumInterfaces == 1;
 	int ret;
 
 	uea_dbg(usb, "ADSL device found with vid (%#X) pid (%#X) Rev (%#X): %s\n",
@@ -2559,6 +2560,22 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
 		le16_to_cpu(usb->descriptor.bcdDevice),
 		chip_name[UEA_CHIP_VERSION(id)]);
 
+	/*
+	 * uea_probe() decides between the pre-firmware and post-firmware case
+	 * from the USB id and stores a different object as interface data in
+	 * each case: a struct completion for a pre-firmware device, a struct
+	 * usbatm_data for a post-firmware one. uea_disconnect() instead tells
+	 * the two apart by the number of interfaces (a pre-firmware device
+	 * exposes a single interface, ADI930 has 2 and eagle has 3). A crafted
+	 * device advertising a pre-firmware id together with a multi-interface
+	 * descriptor (or the other way around) makes the two disagree, so that
+	 * usbatm_usb_disconnect() treats the small completion object as a
+	 * struct usbatm_data and reads out of bounds. Reject such inconsistent
+	 * descriptors so both paths make the same decision.
+	 */
+	if (UEA_IS_PREFIRM(id) != single_iface)
+		return -ENODEV;
+
 	usb_reset_device(usb);
 
 	if (UEA_IS_PREFIRM(id)) {
Signature · 1 line
2.53.0
author maintainer
#212 lore raw

PATCH 212/744 drivers/virt: pkvm: Fix end calculation in mmio_guard_ioremap_hook()

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Mostafa Saleh <[email protected]>

[ Upstream commit 62c740f823a8e47ffe56e45a7472c27cf988e2f6 ]

Sashiko (locally) reports a logical issues in mmio_guard_ioremap_hook()

mmio_guard_ioremap_hook() attempts to handle unaligned addresses and sizes. However, aligning the start address before adding the size, might shift the end to the page before.

Fixes 0f1269495800 ("drivers/virt: pkvm: Intercept ioremap using pKVM MMIO_GUARD hypercall")
---
 drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c +1 -1
index 4230b817a80bd8..d66291def0f408 100644
@@ -82,8 +82,8 @@ static int mmio_guard_ioremap_hook(phys_addr_t phys, size_t size,
 	if (protval != PROT_DEVICE_nGnRE && protval != PROT_DEVICE_nGnRnE)
 		return 0;
 
+	end = PAGE_ALIGN(phys + size);
 	phys = PAGE_ALIGN_DOWN(phys);
-	end = phys + PAGE_ALIGN(size);
 
 	while (phys < end) {
 		const int func_id = ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_FUNC_ID;
Signature · 1 line
2.53.0
author maintainer
#213 lore raw

PATCH 213/744 hwmon: Drop unused i2c driver_data

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Uwe Kleine-König (The Capable Hub) <[email protected]>

[ Upstream commit b3de407ae66ffef6290a31363205e9751db0537a ]

The four drivers all don't make use of the value that was explicitly assigned to the .driver_data member. Drop the assignment.

While touching these lines also make the assignments use named initializers and drop a comma after the end-of-list marker.

Stable-dep-of: af01dab0c39a ("hwmon: (pmbus/max34440) block unsupported VIN and IIN limit registers")

---
 drivers/hwmon/lm80.c          | 4 ++--
 drivers/hwmon/pmbus/aps-379.c | 4 ++--
 drivers/hwmon/pmbus/lt3074.c  | 4 ++--
 drivers/hwmon/tsc1641.c       | 2 +-
 4 files changed, 7 insertions(+), 7 deletions(-)
drivers/hwmon/lm80.c +2 -2
index 63c7831bd3e11b..002c669182e153 100644
@@ -622,8 +622,8 @@ static int lm80_probe(struct i2c_client *client)
  */
 
 static const struct i2c_device_id lm80_id[] = {
-	{ "lm80", 0 },
-	{ "lm96080", 1 },
+	{ "lm80" },
+	{ "lm96080" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, lm80_id);
drivers/hwmon/pmbus/aps-379.c +2 -2
index 7d46cd647e20aa..3ec0940ae56444 100644
@@ -100,8 +100,8 @@ static struct pmbus_driver_info aps_379_info = {
 };
 
 static const struct i2c_device_id aps_379_id[] = {
-	{ "aps-379", 0 },
-	{},
+	{ .name = "aps-379" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, aps_379_id);
 
drivers/hwmon/pmbus/lt3074.c +2 -2
index 3704dbe7b54ab8..ed932ddb4f77b6 100644
@@ -95,8 +95,8 @@ static int lt3074_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id lt3074_id[] = {
-	{ "lt3074", 0 },
-	{}
+	{ .name = "lt3074" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, lt3074_id);
 
drivers/hwmon/tsc1641.c +1 -1
index 2b5d34bab146df..fc53cd5bb6e099 100644
@@ -721,7 +721,7 @@ static int tsc1641_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id tsc1641_id[] = {
-	{ "tsc1641", 0 },
+	{ .name = "tsc1641" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, tsc1641_id);
Signature · 1 line
2.53.0
author maintainer
#214 lore raw

PATCH 214/744 hwmon: Use named initializers for arrays of i2c_device_data

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Uwe Kleine-König (The Capable Hub) <[email protected]>

[ Upstream commit 4a9e6a9230c88a71916301b9fe6627413ebc2574 ]

While being less compact, using named initializers allows to more easily see which members of the structs are assigned which value without having to lookup the declaration of the struct. And it's also more robust against changes to the struct definition.

The mentioned robustness is relevant for a planned change to struct i2c_device_id that replaces .driver_data by an anonymous union.

While touching all these arrays, unify indention and usage of commas.

This patch doesn't modify the compiled arrays, only their representation in source form benefits. The former was confirmed with x86 and arm64 builds.

Stable-dep-of: af01dab0c39a ("hwmon: (pmbus/max34440) block unsupported VIN and IIN limit registers")

---
 drivers/hwmon/ad7414.c                  |  4 +-
 drivers/hwmon/ad7418.c                  |  6 +-
 drivers/hwmon/adc128d818.c              |  2 +-
 drivers/hwmon/adm1025.c                 |  4 +-
 drivers/hwmon/adm1026.c                 |  2 +-
 drivers/hwmon/adm1029.c                 |  2 +-
 drivers/hwmon/adm1031.c                 |  4 +-
 drivers/hwmon/adm1177.c                 |  4 +-
 drivers/hwmon/adm9240.c                 |  6 +-
 drivers/hwmon/ads7828.c                 |  4 +-
 drivers/hwmon/adt7410.c                 |  8 +--
 drivers/hwmon/adt7411.c                 |  2 +-
 drivers/hwmon/adt7462.c                 |  2 +-
 drivers/hwmon/adt7470.c                 |  2 +-
 drivers/hwmon/adt7475.c                 |  8 +--
 drivers/hwmon/aht10.c                   |  8 +--
 drivers/hwmon/amc6821.c                 |  2 +-
 drivers/hwmon/asb100.c                  |  2 +-
 drivers/hwmon/asc7621.c                 |  6 +-
 drivers/hwmon/atxp1.c                   |  2 +-
 drivers/hwmon/chipcap2.c                | 16 ++---
 drivers/hwmon/dme1737.c                 |  4 +-
 drivers/hwmon/ds1621.c                  | 10 +--
 drivers/hwmon/ds620.c                   |  4 +-
 drivers/hwmon/emc1403.c                 | 24 +++----
 drivers/hwmon/emc2103.c                 |  2 +-
 drivers/hwmon/emc2305.c                 |  8 +--
 drivers/hwmon/emc6w201.c                |  2 +-
 drivers/hwmon/f75375s.c                 |  6 +-
 drivers/hwmon/fschmd.c                  | 14 ++--
 drivers/hwmon/ftsteutates.c             |  2 +-
 drivers/hwmon/g760a.c                   |  2 +-
 drivers/hwmon/g762.c                    |  6 +-
 drivers/hwmon/gl518sm.c                 |  2 +-
 drivers/hwmon/gl520sm.c                 |  2 +-
 drivers/hwmon/hih6130.c                 |  2 +-
 drivers/hwmon/hs3001.c                  |  4 +-
 drivers/hwmon/htu31.c                   |  2 +-
 drivers/hwmon/ina209.c                  |  2 +-
 drivers/hwmon/ina238.c                  | 12 ++--
 drivers/hwmon/ina2xx.c                  | 16 ++---
 drivers/hwmon/ina3221.c                 |  2 +-
 drivers/hwmon/isl28022.c                |  2 +-
 drivers/hwmon/jc42.c                    |  2 +-
 drivers/hwmon/lineage-pem.c             |  4 +-
 drivers/hwmon/lm63.c                    |  6 +-
 drivers/hwmon/lm73.c                    |  2 +-
 drivers/hwmon/lm75.c                    | 62 ++++++++--------
 drivers/hwmon/lm77.c                    |  2 +-
 drivers/hwmon/lm78.c                    |  4 +-
 drivers/hwmon/lm80.c                    |  4 +-
 drivers/hwmon/lm83.c                    |  4 +-
 drivers/hwmon/lm85.c                    | 24 +++----
 drivers/hwmon/lm87.c                    |  4 +-
 drivers/hwmon/lm90.c                    | 96 ++++++++++++-------------
 drivers/hwmon/lm92.c                    |  6 +-
 drivers/hwmon/lm93.c                    |  4 +-
 drivers/hwmon/lm95234.c                 |  4 +-
 drivers/hwmon/lm95241.c                 |  4 +-
 drivers/hwmon/lm95245.c                 |  4 +-
 drivers/hwmon/ltc2945.c                 |  2 +-
 drivers/hwmon/ltc2947-i2c.c             |  4 +-
 drivers/hwmon/ltc2990.c                 |  4 +-
 drivers/hwmon/ltc2991.c                 |  4 +-
 drivers/hwmon/ltc2992.c                 |  4 +-
 drivers/hwmon/ltc4151.c                 |  2 +-
 drivers/hwmon/ltc4215.c                 |  2 +-
 drivers/hwmon/ltc4222.c                 |  2 +-
 drivers/hwmon/ltc4245.c                 |  2 +-
 drivers/hwmon/ltc4260.c                 |  2 +-
 drivers/hwmon/ltc4261.c                 |  4 +-
 drivers/hwmon/max127.c                  |  2 +-
 drivers/hwmon/max16065.c                | 12 ++--
 drivers/hwmon/max1619.c                 |  2 +-
 drivers/hwmon/max1668.c                 |  6 +-
 drivers/hwmon/max31730.c                |  2 +-
 drivers/hwmon/max31760.c                |  2 +-
 drivers/hwmon/max31790.c                |  2 +-
 drivers/hwmon/max31827.c                |  6 +-
 drivers/hwmon/max6620.c                 |  2 +-
 drivers/hwmon/max6621.c                 |  2 +-
 drivers/hwmon/max6639.c                 |  2 +-
 drivers/hwmon/max6650.c                 |  4 +-
 drivers/hwmon/max6697.c                 | 20 +++---
 drivers/hwmon/mc34vr500.c               |  4 +-
 drivers/hwmon/mcp3021.c                 |  4 +-
 drivers/hwmon/nct6775-i2c.c             | 26 +++----
 drivers/hwmon/nct7802.c                 |  2 +-
 drivers/hwmon/nct7904.c                 |  4 +-
 drivers/hwmon/pcf8591.c                 |  2 +-
 drivers/hwmon/pmbus/acbel-fsg032.c      |  4 +-
 drivers/hwmon/pmbus/adm1266.c           |  2 +-
 drivers/hwmon/pmbus/adm1275.c           | 20 +++---
 drivers/hwmon/pmbus/bel-pfe.c           |  6 +-
 drivers/hwmon/pmbus/bpa-rs600.c         |  6 +-
 drivers/hwmon/pmbus/crps.c              |  4 +-
 drivers/hwmon/pmbus/delta-ahe50dc-fan.c |  2 +-
 drivers/hwmon/pmbus/dps920ab.c          |  4 +-
 drivers/hwmon/pmbus/fsp-3y.c            |  4 +-
 drivers/hwmon/pmbus/hac300s.c           |  4 +-
 drivers/hwmon/pmbus/ibm-cffps.c         |  8 +--
 drivers/hwmon/pmbus/ina233.c            |  4 +-
 drivers/hwmon/pmbus/inspur-ipsps.c      |  4 +-
 drivers/hwmon/pmbus/ir35221.c           |  4 +-
 drivers/hwmon/pmbus/ir36021.c           |  4 +-
 drivers/hwmon/pmbus/ir38064.c           | 10 +--
 drivers/hwmon/pmbus/irps5401.c          |  4 +-
 drivers/hwmon/pmbus/isl68137.c          | 96 ++++++++++++-------------
 drivers/hwmon/pmbus/lm25066.c           | 10 +--
 drivers/hwmon/pmbus/lt7182s.c           |  4 +-
 drivers/hwmon/pmbus/ltc2978.c           | 60 ++++++++--------
 drivers/hwmon/pmbus/ltc3815.c           |  2 +-
 drivers/hwmon/pmbus/max15301.c          |  8 +--
 drivers/hwmon/pmbus/max16064.c          |  4 +-
 drivers/hwmon/pmbus/max16601.c          | 10 +--
 drivers/hwmon/pmbus/max17616.c          |  2 +-
 drivers/hwmon/pmbus/max20730.c          | 10 +--
 drivers/hwmon/pmbus/max20751.c          |  4 +-
 drivers/hwmon/pmbus/max31785.c          |  8 +--
 drivers/hwmon/pmbus/max34440.c          | 18 ++---
 drivers/hwmon/pmbus/max8688.c           |  2 +-
 drivers/hwmon/pmbus/mp2856.c            |  6 +-
 drivers/hwmon/pmbus/mp2888.c            |  4 +-
 drivers/hwmon/pmbus/mp2891.c            |  2 +-
 drivers/hwmon/pmbus/mp2925.c            |  6 +-
 drivers/hwmon/pmbus/mp29502.c           |  4 +-
 drivers/hwmon/pmbus/mp2975.c            |  8 +--
 drivers/hwmon/pmbus/mp2993.c            |  2 +-
 drivers/hwmon/pmbus/mp5920.c            |  2 +-
 drivers/hwmon/pmbus/mp5926.c            |  4 +-
 drivers/hwmon/pmbus/mp5990.c            |  4 +-
 drivers/hwmon/pmbus/mp9941.c            |  2 +-
 drivers/hwmon/pmbus/mp9945.c            |  4 +-
 drivers/hwmon/pmbus/mpq7932.c           |  6 +-
 drivers/hwmon/pmbus/mpq8785.c           | 10 +--
 drivers/hwmon/pmbus/pim4328.c           | 18 ++---
 drivers/hwmon/pmbus/pli1209bc.c         |  4 +-
 drivers/hwmon/pmbus/pm6764tr.c          |  4 +-
 drivers/hwmon/pmbus/pmbus.c             | 60 ++++++++--------
 drivers/hwmon/pmbus/pxe1610.c           |  8 +--
 drivers/hwmon/pmbus/q54sj108a2.c        |  8 +--
 drivers/hwmon/pmbus/stef48h28.c         |  4 +-
 drivers/hwmon/pmbus/stpddc60.c          |  6 +-
 drivers/hwmon/pmbus/tda38640.c          |  4 +-
 drivers/hwmon/pmbus/tps25990.c          |  4 +-
 drivers/hwmon/pmbus/tps40422.c          |  4 +-
 drivers/hwmon/pmbus/tps53679.c          | 18 ++---
 drivers/hwmon/pmbus/tps546d24.c         |  4 +-
 drivers/hwmon/pmbus/ucd9000.c           | 16 ++---
 drivers/hwmon/pmbus/ucd9200.c           | 18 ++---
 drivers/hwmon/pmbus/xdp710.c            |  2 +-
 drivers/hwmon/pmbus/xdp720.c            |  4 +-
 drivers/hwmon/pmbus/xdpe12284.c         |  8 +--
 drivers/hwmon/pmbus/xdpe152c4.c         |  6 +-
 drivers/hwmon/pmbus/xdpe1a2g7b.c        |  6 +-
 drivers/hwmon/pmbus/zl6100.c            | 44 ++++++------
 drivers/hwmon/powr1220.c                |  4 +-
 drivers/hwmon/pt5161l.c                 |  4 +-
 drivers/hwmon/sbtsi_temp.c              |  4 +-
 drivers/hwmon/sg2042-mcu.c              |  2 +-
 drivers/hwmon/sht21.c                   |  6 +-
 drivers/hwmon/sht3x.c                   |  8 +--
 drivers/hwmon/sht4x.c                   |  4 +-
 drivers/hwmon/shtc1.c                   |  6 +-
 drivers/hwmon/smsc47m192.c              |  2 +-
 drivers/hwmon/spd5118.c                 |  2 +-
 drivers/hwmon/stts751.c                 |  2 +-
 drivers/hwmon/tc654.c                   |  6 +-
 drivers/hwmon/tc74.c                    |  4 +-
 drivers/hwmon/thmc50.c                  |  4 +-
 drivers/hwmon/tmp102.c                  |  2 +-
 drivers/hwmon/tmp103.c                  |  2 +-
 drivers/hwmon/tmp108.c                  |  8 +--
 drivers/hwmon/tmp401.c                  | 10 +--
 drivers/hwmon/tmp421.c                  | 10 +--
 drivers/hwmon/tmp464.c                  |  4 +-
 drivers/hwmon/tmp513.c                  |  4 +-
 drivers/hwmon/w83773g.c                 |  2 +-
 drivers/hwmon/w83781d.c                 |  8 +--
 drivers/hwmon/w83791d.c                 |  2 +-
 drivers/hwmon/w83792d.c                 |  2 +-
 drivers/hwmon/w83793.c                  |  2 +-
 drivers/hwmon/w83795.c                  |  4 +-
 drivers/hwmon/w83l785ts.c               |  2 +-
 drivers/hwmon/w83l786ng.c               |  2 +-
 185 files changed, 684 insertions(+), 684 deletions(-)
drivers/hwmon/ad7414.c +2 -2
index f0b17e59827f91..c2df631ae93a39 100644
@@ -205,8 +205,8 @@ static int ad7414_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ad7414_id[] = {
-	{ "ad7414" },
-	{}
+	{ .name = "ad7414" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ad7414_id);
 
drivers/hwmon/ad7418.c +3 -3
index 7a132accdf8a3f..a0c9cf5e12cc40 100644
@@ -281,9 +281,9 @@ static int ad7418_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ad7418_id[] = {
-	{ "ad7416", ad7416 },
-	{ "ad7417", ad7417 },
-	{ "ad7418", ad7418 },
+	{ .name = "ad7416", .driver_data = ad7416 },
+	{ .name = "ad7417", .driver_data = ad7417 },
+	{ .name = "ad7418", .driver_data = ad7418 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ad7418_id);
drivers/hwmon/adc128d818.c +1 -1
index 5e805d4ee76ab4..e45adc0b84d1c0 100644
@@ -480,7 +480,7 @@ static int adc128_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id adc128_id[] = {
-	{ "adc128d818" },
+	{ .name = "adc128d818" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adc128_id);
drivers/hwmon/adm1025.c +2 -2
index 389382d54752e4..ccac7ba601e99d 100644
@@ -548,8 +548,8 @@ static int adm1025_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id adm1025_id[] = {
-	{ "adm1025", adm1025 },
-	{ "ne1619", ne1619 },
+	{ .name = "adm1025", .driver_data = adm1025 },
+	{ .name = "ne1619", .driver_data = ne1619 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adm1025_id);
drivers/hwmon/adm1026.c +1 -1
index c38c932e5d2af6..3ad82c01f81d5e 100644
@@ -1857,7 +1857,7 @@ static int adm1026_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id adm1026_id[] = {
-	{ "adm1026" },
+	{ .name = "adm1026" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adm1026_id);
drivers/hwmon/adm1029.c +1 -1
index 71eea8ae51b95f..6cb0a238e059b9 100644
@@ -382,7 +382,7 @@ static int adm1029_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id adm1029_id[] = {
-	{ "adm1029" },
+	{ .name = "adm1029" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adm1029_id);
drivers/hwmon/adm1031.c +2 -2
index 343118532cdb4f..24d0d4146c8774 100644
@@ -1055,8 +1055,8 @@ static int adm1031_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id adm1031_id[] = {
-	{ "adm1030", adm1030 },
-	{ "adm1031", adm1031 },
+	{ .name = "adm1030", .driver_data = adm1030 },
+	{ .name = "adm1031", .driver_data = adm1031 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adm1031_id);
drivers/hwmon/adm1177.c +2 -2
index 7888afe8dafd66..dc4d8a214d1b48 100644
@@ -246,8 +246,8 @@ static int adm1177_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id adm1177_id[] = {
-	{"adm1177"},
-	{}
+	{ .name = "adm1177" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adm1177_id);
 
drivers/hwmon/adm9240.c +3 -3
index 86f6044b5bd04d..586650e8d043f8 100644
@@ -794,9 +794,9 @@ static int adm9240_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id adm9240_id[] = {
-	{ "adm9240", adm9240 },
-	{ "ds1780", ds1780 },
-	{ "lm81", lm81 },
+	{ .name = "adm9240", .driver_data = adm9240 },
+	{ .name = "ds1780", .driver_data = ds1780 },
+	{ .name = "lm81", .driver_data = lm81 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adm9240_id);
drivers/hwmon/ads7828.c +2 -2
index 7f43565ca28416..149cfcec78dcc2 100644
@@ -176,8 +176,8 @@ static int ads7828_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ads7828_device_ids[] = {
-	{ "ads7828", ads7828 },
-	{ "ads7830", ads7830 },
+	{ .name = "ads7828", .driver_data = ads7828 },
+	{ .name = "ads7830", .driver_data = ads7830 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ads7828_device_ids);
drivers/hwmon/adt7410.c +4 -4
index 73b196a78f3a09..0aa7ce0a04be0d 100644
@@ -89,10 +89,10 @@ static int adt7410_i2c_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id adt7410_ids[] = {
-	{ "adt7410" },
-	{ "adt7420" },
-	{ "adt7422" },
-	{}
+	{ .name = "adt7410" },
+	{ .name = "adt7420" },
+	{ .name = "adt7422" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adt7410_ids);
 
drivers/hwmon/adt7411.c +1 -1
index b9991a69e6c60e..5dce2a70172588 100644
@@ -670,7 +670,7 @@ static int adt7411_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id adt7411_id[] = {
-	{ "adt7411" },
+	{ .name = "adt7411" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adt7411_id);
drivers/hwmon/adt7462.c +1 -1
index 174dfee47f7a78..5101d30ed9c682 100644
@@ -1809,7 +1809,7 @@ static int adt7462_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id adt7462_id[] = {
-	{ "adt7462" },
+	{ .name = "adt7462" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adt7462_id);
drivers/hwmon/adt7470.c +1 -1
index dbee6926fa0555..664349756dc2bf 100644
@@ -1296,7 +1296,7 @@ static void adt7470_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id adt7470_id[] = {
-	{ "adt7470" },
+	{ .name = "adt7470" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adt7470_id);
drivers/hwmon/adt7475.c +4 -4
index 8cefa14e1633b9..7fb96f5395fa63 100644
@@ -165,10 +165,10 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
 enum chips { adt7473, adt7475, adt7476, adt7490 };
 
 static const struct i2c_device_id adt7475_id[] = {
-	{ "adt7473", adt7473 },
-	{ "adt7475", adt7475 },
-	{ "adt7476", adt7476 },
-	{ "adt7490", adt7490 },
+	{ .name = "adt7473", .driver_data = adt7473 },
+	{ .name = "adt7475", .driver_data = adt7475 },
+	{ .name = "adt7476", .driver_data = adt7476 },
+	{ .name = "adt7490", .driver_data = adt7490 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adt7475_id);
drivers/hwmon/aht10.c +4 -4
index 66955395d05839..6c263cb577666c 100644
@@ -55,10 +55,10 @@
 enum aht10_variant { aht10, aht20, dht20};
 
 static const struct i2c_device_id aht10_id[] = {
-	{ "aht10", aht10 },
-	{ "aht20", aht20 },
-	{ "dht20", dht20 },
-	{ },
+	{ .name = "aht10", .driver_data = aht10 },
+	{ .name = "aht20", .driver_data = aht20 },
+	{ .name = "dht20", .driver_data = dht20 },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, aht10_id);
 
drivers/hwmon/amc6821.c +1 -1
index d5f864b360b03b..bbc0542a7d380a 100644
@@ -1083,7 +1083,7 @@ static int amc6821_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id amc6821_id[] = {
-	{ "amc6821" },
+	{ .name = "amc6821" },
 	{ }
 };
 
drivers/hwmon/asb100.c +1 -1
index 14e7737866c25b..5f5c945051665b 100644
@@ -213,7 +213,7 @@ static struct asb100_data *asb100_update_device(struct device *dev);
 static void asb100_init_client(struct i2c_client *client);
 
 static const struct i2c_device_id asb100_id[] = {
-	{ "asb100" },
+	{ .name = "asb100" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, asb100_id);
drivers/hwmon/asc7621.c +3 -3
index 87e1867008499b..e8145bb13ab34a 100644
@@ -1179,9 +1179,9 @@ static void asc7621_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id asc7621_id[] = {
-	{"asc7621", asc7621},
-	{"asc7621a", asc7621a},
-	{},
+	{ .name = "asc7621", .driver_data = asc7621 },
+	{ .name = "asc7621a", .driver_data = asc7621a },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, asc7621_id);
drivers/hwmon/atxp1.c +1 -1
index 1c7e9a98b757c3..f5de4894f0a2e3 100644
@@ -278,7 +278,7 @@ static int atxp1_probe(struct i2c_client *client)
 };
 
 static const struct i2c_device_id atxp1_id[] = {
-	{ "atxp1" },
+	{ .name = "atxp1" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, atxp1_id);
drivers/hwmon/chipcap2.c +8 -8
index 645b8c2e704e6b..4aecf463180fd7 100644
@@ -736,14 +736,14 @@ static void cc2_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id cc2_id[] = {
-	{ "cc2d23" },
-	{ "cc2d23s" },
-	{ "cc2d25" },
-	{ "cc2d25s" },
-	{ "cc2d33" },
-	{ "cc2d33s" },
-	{ "cc2d35" },
-	{ "cc2d35s" },
+	{ .name = "cc2d23" },
+	{ .name = "cc2d23s" },
+	{ .name = "cc2d25" },
+	{ .name = "cc2d25s" },
+	{ .name = "cc2d33" },
+	{ .name = "cc2d33s" },
+	{ .name = "cc2d35" },
+	{ .name = "cc2d35s" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, cc2_id);
drivers/hwmon/dme1737.c +2 -2
index 3d4057309950dc..7e839308e58fa3 100644
@@ -2515,8 +2515,8 @@ static void dme1737_i2c_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id dme1737_id[] = {
-	{ "dme1737", dme1737 },
-	{ "sch5027", sch5027 },
+	{ .name = "dme1737", .driver_data = dme1737 },
+	{ .name = "sch5027", .driver_data = sch5027 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, dme1737_id);
drivers/hwmon/ds1621.c +5 -5
index 42ec34cb8a5f87..0618f6de9679c4 100644
@@ -367,11 +367,11 @@ static int ds1621_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ds1621_id[] = {
-	{ "ds1621", ds1621 },
-	{ "ds1625", ds1625 },
-	{ "ds1631", ds1631 },
-	{ "ds1721", ds1721 },
-	{ "ds1731", ds1731 },
+	{ .name = "ds1621", .driver_data = ds1621 },
+	{ .name = "ds1625", .driver_data = ds1625 },
+	{ .name = "ds1631", .driver_data = ds1631 },
+	{ .name = "ds1721", .driver_data = ds1721 },
+	{ .name = "ds1731", .driver_data = ds1731 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ds1621_id);
drivers/hwmon/ds620.c +2 -2
index ce397042d90b86..25287f0fa4c2e4 100644
@@ -233,8 +233,8 @@ static int ds620_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ds620_id[] = {
-	{"ds620"},
-	{}
+	{ .name = "ds620" },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, ds620_id);
drivers/hwmon/emc1403.c +12 -12
index 964a8cb278f16a..cd753b38709f25 100644
@@ -639,18 +639,18 @@ static const struct hwmon_chip_info emc1403_chip_info = {
 
 /* Last digit of chip name indicates number of channels */
 static const struct i2c_device_id emc1403_idtable[] = {
-	{ "emc1402", emc1402 },
-	{ "emc1403", emc1403 },
-	{ "emc1404", emc1404 },
-	{ "emc1412", emc1402 },
-	{ "emc1413", emc1403 },
-	{ "emc1414", emc1404 },
-	{ "emc1422", emc1402 },
-	{ "emc1423", emc1403 },
-	{ "emc1424", emc1404 },
-	{ "emc1428", emc1428 },
-	{ "emc1438", emc1428 },
-	{ "emc1442", emc1402 },
+	{ .name = "emc1402", .driver_data = emc1402 },
+	{ .name = "emc1403", .driver_data = emc1403 },
+	{ .name = "emc1404", .driver_data = emc1404 },
+	{ .name = "emc1412", .driver_data = emc1402 },
+	{ .name = "emc1413", .driver_data = emc1403 },
+	{ .name = "emc1414", .driver_data = emc1404 },
+	{ .name = "emc1422", .driver_data = emc1402 },
+	{ .name = "emc1423", .driver_data = emc1403 },
+	{ .name = "emc1424", .driver_data = emc1404 },
+	{ .name = "emc1428", .driver_data = emc1428 },
+	{ .name = "emc1438", .driver_data = emc1428 },
+	{ .name = "emc1442", .driver_data = emc1402 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, emc1403_idtable);
drivers/hwmon/emc2103.c +1 -1
index 9b8e925af03002..27dc149a3ed995 100644
@@ -624,7 +624,7 @@ emc2103_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id emc2103_ids[] = {
-	{ "emc2103" },
+	{ .name = "emc2103" },
 	{ /* LIST END */ }
 };
 MODULE_DEVICE_TABLE(i2c, emc2103_ids);
drivers/hwmon/emc2305.c +4 -4
index 64b213e1451e70..8fcdac6cfb24dc 100644
@@ -59,10 +59,10 @@ enum emc230x_product_id {
 };
 
 static const struct i2c_device_id emc2305_ids[] = {
-	{ "emc2305" },
-	{ "emc2303" },
-	{ "emc2302" },
-	{ "emc2301" },
+	{ .name = "emc2305" },
+	{ .name = "emc2303" },
+	{ .name = "emc2302" },
+	{ .name = "emc2301" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, emc2305_ids);
drivers/hwmon/emc6w201.c +1 -1
index 1100c6e5daa775..c13ea874868356 100644
@@ -464,7 +464,7 @@ static int emc6w201_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id emc6w201_id[] = {
-	{ "emc6w201" },
+	{ .name = "emc6w201" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, emc6w201_id);
drivers/hwmon/f75375s.c +3 -3
index 7e867f13242013..cc3a9612f2c0af 100644
@@ -877,9 +877,9 @@ static int f75375_detect(struct i2c_client *client,
 }
 
 static const struct i2c_device_id f75375_id[] = {
-	{ "f75373", f75373 },
-	{ "f75375", f75375 },
-	{ "f75387", f75387 },
+	{ .name = "f75373", .driver_data = f75373 },
+	{ .name = "f75375", .driver_data = f75375 },
+	{ .name = "f75387", .driver_data = f75387 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, f75375_id);
drivers/hwmon/fschmd.c +7 -7
index 1211fa2259e52e..019fc32bf3181a 100644
@@ -225,13 +225,13 @@ static struct fschmd_data *fschmd_update_device(struct device *dev);
  */
 
 static const struct i2c_device_id fschmd_id[] = {
-	{ "fscpos", fscpos },
-	{ "fscher", fscher },
-	{ "fscscy", fscscy },
-	{ "fschrc", fschrc },
-	{ "fschmd", fschmd },
-	{ "fschds", fschds },
-	{ "fscsyl", fscsyl },
+	{ .name = "fscpos", .driver_data = fscpos },
+	{ .name = "fscher", .driver_data = fscher },
+	{ .name = "fscscy", .driver_data = fscscy },
+	{ .name = "fschrc", .driver_data = fschrc },
+	{ .name = "fschmd", .driver_data = fschmd },
+	{ .name = "fschds", .driver_data = fschds },
+	{ .name = "fscsyl", .driver_data = fscsyl },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, fschmd_id);
drivers/hwmon/ftsteutates.c +1 -1
index 08dcc6a7fb6255..06be120a349d63 100644
@@ -49,7 +49,7 @@
 static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
 
 static const struct i2c_device_id fts_id[] = {
-	{ "ftsteutates" },
+	{ .name = "ftsteutates" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, fts_id);
drivers/hwmon/g760a.c +1 -1
index 39ae8f82641761..e2166ee7628607 100644
@@ -197,7 +197,7 @@ static int g760a_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id g760a_id[] = {
-	{ "g760a" },
+	{ .name = "g760a" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, g760a_id);
drivers/hwmon/g762.c +3 -3
index 4fa3aa1271daa8..407cf7af4fdd91 100644
@@ -44,9 +44,9 @@
 #define DRVNAME "g762"
 
 static const struct i2c_device_id g762_id[] = {
-	{ "g761" },
-	{ "g762" },
-	{ "g763" },
+	{ .name = "g761" },
+	{ .name = "g762" },
+	{ .name = "g763" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, g762_id);
drivers/hwmon/gl518sm.c +1 -1
index 9c68bc0139503c..742c130cec7f1a 100644
@@ -642,7 +642,7 @@ static int gl518_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id gl518_id[] = {
-	{ "gl518sm" },
+	{ .name = "gl518sm" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, gl518_id);
drivers/hwmon/gl520sm.c +1 -1
index 972f4f8caa2b7a..f4fe39912ee292 100644
@@ -885,7 +885,7 @@ static int gl520_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id gl520_id[] = {
-	{ "gl520sm" },
+	{ .name = "gl520sm" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, gl520_id);
drivers/hwmon/hih6130.c +1 -1
index 85af8299150a52..7984be1e706d55 100644
@@ -233,7 +233,7 @@ static int hih6130_probe(struct i2c_client *client)
 
 /* Device ID table */
 static const struct i2c_device_id hih6130_id[] = {
-	{ "hih6130" },
+	{ .name = "hih6130" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, hih6130_id);
drivers/hwmon/hs3001.c +2 -2
index 50c6c15f8b180b..b263cbeca0747f 100644
@@ -169,8 +169,8 @@ static const struct hwmon_chip_info hs3001_chip_info = {
 
 /* device ID table */
 static const struct i2c_device_id hs3001_ids[] = {
-	{ "hs3001" },
-	{ },
+	{ .name = "hs3001" },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, hs3001_ids);
drivers/hwmon/htu31.c +1 -1
index 7521a371aa6cdf..5d2cdbdb773b07 100644
@@ -322,7 +322,7 @@ static int htu31_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id htu31_id[] = {
-	{ "htu31" },
+	{ .name = "htu31" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, htu31_id);
drivers/hwmon/ina209.c +1 -1
index a116f1600e810f..39aca2cdf27f7f 100644
@@ -569,7 +569,7 @@ static void ina209_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ina209_id[] = {
-	{ "ina209" },
+	{ .name = "ina209" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ina209_id);
drivers/hwmon/ina238.c +6 -6
index ff67b03189f73c..c20dd164a6a6c9 100644
@@ -837,12 +837,12 @@ static int ina238_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ina238_id[] = {
-	{ "ina228", ina228 },
-	{ "ina237", ina237 },
-	{ "ina238", ina238 },
-	{ "ina700", ina700 },
-	{ "ina780", ina780 },
-	{ "sq52206", sq52206 },
+	{ .name = "ina228", .driver_data = ina228 },
+	{ .name = "ina237", .driver_data = ina237 },
+	{ .name = "ina238", .driver_data = ina238 },
+	{ .name = "ina700", .driver_data = ina700 },
+	{ .name = "ina780", .driver_data = ina780 },
+	{ .name = "sq52206", .driver_data = sq52206 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ina238_id);
drivers/hwmon/ina2xx.c +8 -8
index 613ffb622b7c42..32bf4595bcb482 100644
@@ -1000,14 +1000,14 @@ static int ina2xx_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ina2xx_id[] = {
-	{ "ina219", ina219 },
-	{ "ina220", ina219 },
-	{ "ina226", ina226 },
-	{ "ina230", ina226 },
-	{ "ina231", ina226 },
-	{ "ina234", ina234 },
-	{ "ina260", ina260 },
-	{ "sy24655", sy24655 },
+	{ .name = "ina219", .driver_data = ina219 },
+	{ .name = "ina220", .driver_data = ina219 },
+	{ .name = "ina226", .driver_data = ina226 },
+	{ .name = "ina230", .driver_data = ina226 },
+	{ .name = "ina231", .driver_data = ina226 },
+	{ .name = "ina234", .driver_data = ina234 },
+	{ .name = "ina260", .driver_data = ina260 },
+	{ .name = "sy24655", .driver_data = sy24655 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ina2xx_id);
drivers/hwmon/ina3221.c +1 -1
index 5ecc68dcf16987..3ab5de3a111029 100644
@@ -1002,7 +1002,7 @@ static const struct of_device_id ina3221_of_match_table[] = {
 MODULE_DEVICE_TABLE(of, ina3221_of_match_table);
 
 static const struct i2c_device_id ina3221_ids[] = {
-	{ "ina3221" },
+	{ .name = "ina3221" },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(i2c, ina3221_ids);
drivers/hwmon/isl28022.c +1 -1
index 96fcfbfff48f4c..0c60d2ef28f5dd 100644
@@ -475,7 +475,7 @@ static int isl28022_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id isl28022_ids[] = {
-	{ "isl28022" },
+	{ .name = "isl28022" },
 	{ /* LIST END */ }
 };
 MODULE_DEVICE_TABLE(i2c, isl28022_ids);
drivers/hwmon/jc42.c +1 -1
index 6549dc54378124..77fece680358d9 100644
@@ -579,7 +579,7 @@ static const struct dev_pm_ops jc42_dev_pm_ops = {
 #endif /* CONFIG_PM */
 
 static const struct i2c_device_id jc42_id[] = {
-	{ "jc42" },
+	{ .name = "jc42" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, jc42_id);
drivers/hwmon/lineage-pem.c +2 -2
index 64a335a64a2ebe..2553e49f840158 100644
@@ -502,8 +502,8 @@ static int pem_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id pem_id[] = {
-	{"lineage_pem"},
-	{}
+	{ .name = "lineage_pem" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, pem_id);
 
drivers/hwmon/lm63.c +3 -3
index 30500b4d222129..a0d77a7386a9de 100644
@@ -1152,9 +1152,9 @@ static int lm63_probe(struct i2c_client *client)
  */
 
 static const struct i2c_device_id lm63_id[] = {
-	{ "lm63", lm63 },
-	{ "lm64", lm64 },
-	{ "lm96163", lm96163 },
+	{ .name = "lm63", .driver_data = lm63 },
+	{ .name = "lm64", .driver_data = lm64 },
+	{ .name = "lm96163", .driver_data = lm96163 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, lm63_id);
drivers/hwmon/lm73.c +1 -1
index 581b01572e1bd5..63ee67481a16c2 100644
@@ -220,7 +220,7 @@ lm73_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id lm73_ids[] = {
-	{ "lm73" },
+	{ .name = "lm73" },
 	{ /* LIST END */ }
 };
 MODULE_DEVICE_TABLE(i2c, lm73_ids);
drivers/hwmon/lm75.c +31 -31

68 lines not on this page · raw message

drivers/hwmon/lm77.c +1 -1
index 80f7a6a3f9a29d..96c5c2584d37e7 100644
@@ -337,7 +337,7 @@ static int lm77_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id lm77_id[] = {
-	{ "lm77" },
+	{ .name = "lm77" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, lm77_id);
drivers/hwmon/lm78.c +2 -2
index 9378a47bf5afa9..e4834f9eca6a24 100644
@@ -649,8 +649,8 @@ static int lm78_i2c_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id lm78_i2c_id[] = {
-	{ "lm78", lm78 },
-	{ "lm79", lm79 },
+	{ .name = "lm78", .driver_data = lm78 },
+	{ .name = "lm79", .driver_data = lm79 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, lm78_i2c_id);
drivers/hwmon/lm80.c +2 -2
index 002c669182e153..94f3dabaaa6f62 100644
@@ -622,8 +622,8 @@ static int lm80_probe(struct i2c_client *client)
  */
 
 static const struct i2c_device_id lm80_id[] = {
-	{ "lm80" },
-	{ "lm96080" },
+	{ .name = "lm80" },
+	{ .name = "lm96080" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, lm80_id);
drivers/hwmon/lm83.c +2 -2
index f800fe2ef18b85..8d49df8c9314fd 100644
@@ -443,8 +443,8 @@ static int lm83_probe(struct i2c_client *client)
  */
 
 static const struct i2c_device_id lm83_id[] = {
-	{ "lm83", lm83 },
-	{ "lm82", lm82 },
+	{ .name = "lm83", .driver_data = lm83 },
+	{ .name = "lm82", .driver_data = lm82 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, lm83_id);
drivers/hwmon/lm85.c +12 -12
index 1c244ed75122ea..c56e164d61c185 100644
@@ -1618,18 +1618,18 @@ static int lm85_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id lm85_id[] = {
-	{ "adm1027", adm1027 },
-	{ "adt7463", adt7463 },
-	{ "adt7468", adt7468 },
-	{ "lm85", lm85 },
-	{ "lm85b", lm85 },
-	{ "lm85c", lm85 },
-	{ "lm96000", lm96000 },
-	{ "emc6d100", emc6d100 },
-	{ "emc6d101", emc6d100 },
-	{ "emc6d102", emc6d102 },
-	{ "emc6d103", emc6d103 },
-	{ "emc6d103s", emc6d103s },
+	{ .name = "adm1027", .driver_data = adm1027 },
+	{ .name = "adt7463", .driver_data = adt7463 },
+	{ .name = "adt7468", .driver_data = adt7468 },
+	{ .name = "lm85", .driver_data = lm85 },
+	{ .name = "lm85b", .driver_data = lm85 },
+	{ .name = "lm85c", .driver_data = lm85 },
+	{ .name = "lm96000", .driver_data = lm96000 },
+	{ .name = "emc6d100", .driver_data = emc6d100 },
+	{ .name = "emc6d101", .driver_data = emc6d100 },
+	{ .name = "emc6d102", .driver_data = emc6d102 },
+	{ .name = "emc6d103", .driver_data = emc6d103 },
+	{ .name = "emc6d103s", .driver_data = emc6d103s },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, lm85_id);
drivers/hwmon/lm87.c +2 -2
index 37bf2d1d3d0998..c09074f447083d 100644
@@ -981,8 +981,8 @@ static int lm87_probe(struct i2c_client *client)
  */
 
 static const struct i2c_device_id lm87_id[] = {
-	{ "lm87" },
-	{ "adm1024" },
+	{ .name = "lm87" },
+	{ .name = "adm1024" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, lm87_id);
drivers/hwmon/lm90.c +48 -48

102 lines not on this page · raw message

drivers/hwmon/lm92.c +3 -3
index 91a6b7525bb675..4aadbabc27bb92 100644
@@ -405,10 +405,10 @@ static int lm92_probe(struct i2c_client *client)
  * Module and driver stuff
  */
 
-/* .driver_data is limit register resolution */ 
+/* .driver_data is limit register resolution */
 static const struct i2c_device_id lm92_id[] = {
-	{ "lm92", 13 },
-	{ "max6635", 9 },
+	{ .name = "lm92", .driver_data = 13 },
+	{ .name = "max6635", .driver_data = 9 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, lm92_id);
drivers/hwmon/lm93.c +2 -2
index be4853fad80fdb..d58a3c2a859304 100644
@@ -2624,8 +2624,8 @@ static int lm93_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id lm93_id[] = {
-	{ "lm93" },
-	{ "lm94" },
+	{ .name = "lm93" },
+	{ .name = "lm94" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, lm93_id);
drivers/hwmon/lm95234.c +2 -2
index 387b3ba81dbfc1..74f280b90e3e9c 100644
@@ -532,8 +532,8 @@ static int lm95234_probe(struct i2c_client *client)
 
 /* Driver data (common to all clients) */
 static const struct i2c_device_id lm95234_id[] = {
-	{ "lm95233", lm95233 },
-	{ "lm95234", lm95234 },
+	{ .name = "lm95233", .driver_data = lm95233 },
+	{ .name = "lm95234", .driver_data = lm95234 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, lm95234_id);
drivers/hwmon/lm95241.c +2 -2
index 456381b0938e75..0cb0edb3845db0 100644
@@ -441,8 +441,8 @@ static int lm95241_probe(struct i2c_client *client)
 
 /* Driver data (common to all clients) */
 static const struct i2c_device_id lm95241_id[] = {
-	{ "lm95231" },
-	{ "lm95241" },
+	{ .name = "lm95231" },
+	{ .name = "lm95241" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, lm95241_id);
drivers/hwmon/lm95245.c +2 -2
index 9ed300c6b5f70a..11553391f54b1e 100644
@@ -546,8 +546,8 @@ static int lm95245_probe(struct i2c_client *client)
 
 /* Driver data (common to all clients) */
 static const struct i2c_device_id lm95245_id[] = {
-	{ "lm95235" },
-	{ "lm95245" },
+	{ .name = "lm95235" },
+	{ .name = "lm95245" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, lm95245_id);
drivers/hwmon/ltc2945.c +1 -1
index 3e0e0e0687bdd5..b521100afe53a0 100644
@@ -508,7 +508,7 @@ static int ltc2945_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ltc2945_id[] = {
-	{"ltc2945"},
+	{ .name = "ltc2945" },
 	{ }
 };
 
drivers/hwmon/ltc2947-i2c.c +2 -2
index 176d710706dd9b..e07d33983d5ce3 100644
@@ -27,8 +27,8 @@ static int ltc2947_probe(struct i2c_client *i2c)
 }
 
 static const struct i2c_device_id ltc2947_id[] = {
-	{"ltc2947"},
-	{}
+	{ .name = "ltc2947" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ltc2947_id);
 
drivers/hwmon/ltc2990.c +2 -2
index f1c1933c52cf4f..a2725e4b2f2136 100644
@@ -259,8 +259,8 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c)
 }
 
 static const struct i2c_device_id ltc2990_i2c_id[] = {
-	{ "ltc2990" },
-	{}
+	{ .name = "ltc2990" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ltc2990_i2c_id);
 
drivers/hwmon/ltc2991.c +2 -2
index 6d5d4cb846daf3..bc8d803e8cc90d 100644
@@ -409,8 +409,8 @@ static const struct of_device_id ltc2991_of_match[] = {
 MODULE_DEVICE_TABLE(of, ltc2991_of_match);
 
 static const struct i2c_device_id ltc2991_i2c_id[] = {
-	{ "ltc2991" },
-	{}
+	{ .name = "ltc2991" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ltc2991_i2c_id);
 
drivers/hwmon/ltc2992.c +2 -2
index 2617c4538af91d..43b6029c084048 100644
@@ -948,8 +948,8 @@ static const struct of_device_id ltc2992_of_match[] = {
 MODULE_DEVICE_TABLE(of, ltc2992_of_match);
 
 static const struct i2c_device_id ltc2992_i2c_id[] = {
-	{"ltc2992"},
-	{}
+	{ .name = "ltc2992" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ltc2992_i2c_id);
 
drivers/hwmon/ltc4151.c +1 -1
index fa66eda78efe4f..fa7c57aae5f5fb 100644
@@ -188,7 +188,7 @@ static int ltc4151_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ltc4151_id[] = {
-	{ "ltc4151" },
+	{ .name = "ltc4151" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ltc4151_id);
drivers/hwmon/ltc4215.c +1 -1
index cce452711cec4d..3d439fbbbef93d 100644
@@ -245,7 +245,7 @@ static int ltc4215_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ltc4215_id[] = {
-	{ "ltc4215" },
+	{ .name = "ltc4215" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ltc4215_id);
drivers/hwmon/ltc4222.c +1 -1
index f7eb007fd766bf..4fc69be5f2bc95 100644
@@ -200,7 +200,7 @@ static int ltc4222_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ltc4222_id[] = {
-	{"ltc4222"},
+	{ .name = "ltc4222" },
 	{ }
 };
 
drivers/hwmon/ltc4245.c +1 -1
index e8131a48bda7f7..d87aa9c32c8730 100644
@@ -461,7 +461,7 @@ static int ltc4245_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ltc4245_id[] = {
-	{ "ltc4245" },
+	{ .name = "ltc4245" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ltc4245_id);
drivers/hwmon/ltc4260.c +1 -1
index 9750dc9aa336d4..37a85125d619c8 100644
@@ -163,7 +163,7 @@ static int ltc4260_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ltc4260_id[] = {
-	{"ltc4260"},
+	{ .name = "ltc4260" },
 	{ }
 };
 
drivers/hwmon/ltc4261.c +2 -2
index 2cd218a6a3be7b..a2e52ca0b06e1c 100644
@@ -222,8 +222,8 @@ static int ltc4261_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ltc4261_id[] = {
-	{"ltc4261"},
-	{}
+	{ .name = "ltc4261" },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, ltc4261_id);
drivers/hwmon/max127.c +1 -1
index 5102d86d2619a6..b294e86d52d16e 100644
@@ -312,7 +312,7 @@ static int max127_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id max127_id[] = {
-	{ "max127" },
+	{ .name = "max127" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, max127_id);
drivers/hwmon/max16065.c +6 -6
index 43fbb9b26b102b..f8b4217542203d 100644
@@ -592,12 +592,12 @@ static int max16065_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id max16065_id[] = {
-	{ "max16065", max16065 },
-	{ "max16066", max16066 },
-	{ "max16067", max16067 },
-	{ "max16068", max16068 },
-	{ "max16070", max16070 },
-	{ "max16071", max16071 },
+	{ .name = "max16065", .driver_data = max16065 },
+	{ .name = "max16066", .driver_data = max16066 },
+	{ .name = "max16067", .driver_data = max16067 },
+	{ .name = "max16068", .driver_data = max16068 },
+	{ .name = "max16070", .driver_data = max16070 },
+	{ .name = "max16071", .driver_data = max16071 },
 	{ }
 };
 
drivers/hwmon/max1619.c +1 -1
index 9b6d03cff4df5f..77ef39e8ae7e31 100644
@@ -366,7 +366,7 @@ static int max1619_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id max1619_id[] = {
-	{ "max1619" },
+	{ .name = "max1619" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, max1619_id);
drivers/hwmon/max1668.c +3 -3
index a8197a86f55908..32548f56409ce3 100644
@@ -293,9 +293,9 @@ static int max1668_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id max1668_id[] = {
-	{ "max1668", 5 },
-	{ "max1805", 3 },
-	{ "max1989", 5 },
+	{ .name = "max1668", .driver_data = 5 },
+	{ .name = "max1805", .driver_data = 3 },
+	{ .name = "max1989", .driver_data = 5 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, max1668_id);
drivers/hwmon/max31730.c +1 -1
index 2f4b419b6c9e38..d132be2d6487d0 100644
@@ -345,7 +345,7 @@ max31730_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id max31730_ids[] = {
-	{ "max31730" },
+	{ .name = "max31730" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, max31730_ids);
drivers/hwmon/max31760.c +1 -1
index 127e31ca3c8737..8d3be064b02518 100644
@@ -555,7 +555,7 @@ static const struct of_device_id max31760_of_match[] = {
 MODULE_DEVICE_TABLE(of, max31760_of_match);
 
 static const struct i2c_device_id max31760_id[] = {
-	{"max31760"},
+	{ .name = "max31760" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, max31760_id);
drivers/hwmon/max31790.c +1 -1
index 4f6171a17d9f1f..db8a0f6f18294b 100644
@@ -517,7 +517,7 @@ static int max31790_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id max31790_id[] = {
-	{ "max31790" },
+	{ .name = "max31790" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, max31790_id);
drivers/hwmon/max31827.c +3 -3
index 9b2e56c040df1a..6a7048fdd8ab7a 100644
@@ -463,9 +463,9 @@ static struct attribute *max31827_attrs[] = {
 ATTRIBUTE_GROUPS(max31827);
 
 static const struct i2c_device_id max31827_i2c_ids[] = {
-	{ "max31827", max31827 },
-	{ "max31828", max31828 },
-	{ "max31829", max31829 },
+	{ .name = "max31827", .driver_data = max31827 },
+	{ .name = "max31828", .driver_data = max31828 },
+	{ .name = "max31829", .driver_data = max31829 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, max31827_i2c_ids);
drivers/hwmon/max6620.c +1 -1
index 4316dcdd03fc21..100acf357b5f5b 100644
@@ -474,7 +474,7 @@ static int max6620_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id max6620_id[] = {
-	{ "max6620" },
+	{ .name = "max6620" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, max6620_id);
drivers/hwmon/max6621.c +1 -1
index a7066f3a0bb4e5..e86ec6d237ca63 100644
@@ -537,7 +537,7 @@ static int max6621_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id max6621_id[] = {
-	{ MAX6621_DRV_NAME },
+	{ .name = MAX6621_DRV_NAME },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, max6621_id);
drivers/hwmon/max6639.c +1 -1
index 163d31f17bd49a..dd5f4b3b128dae 100644
@@ -778,7 +778,7 @@ static int max6639_resume(struct device *dev)
 }
 
 static const struct i2c_device_id max6639_id[] = {
-	{"max6639"},
+	{ .name = "max6639" },
 	{ }
 };
 
drivers/hwmon/max6650.c +2 -2
index 56b8157885bbfd..f0140ef9c40ee1 100644
@@ -807,8 +807,8 @@ static int max6650_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id max6650_id[] = {
-	{ "max6650", 1 },
-	{ "max6651", 4 },
+	{ .name = "max6650", .driver_data = 1 },
+	{ .name = "max6651", .driver_data = 4 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, max6650_id);
drivers/hwmon/max6697.c +10 -10
index dd906cf491cae7..c864093f015c02 100644
@@ -564,16 +564,16 @@ static int max6697_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id max6697_id[] = {
-	{ "max6581", max6581 },
-	{ "max6602", max6602 },
-	{ "max6622", max6622 },
-	{ "max6636", max6636 },
-	{ "max6689", max6689 },
-	{ "max6693", max6693 },
-	{ "max6694", max6694 },
-	{ "max6697", max6697 },
-	{ "max6698", max6698 },
-	{ "max6699", max6699 },
+	{ .name = "max6581", .driver_data = max6581 },
+	{ .name = "max6602", .driver_data = max6602 },
+	{ .name = "max6622", .driver_data = max6622 },
+	{ .name = "max6636", .driver_data = max6636 },
+	{ .name = "max6689", .driver_data = max6689 },
+	{ .name = "max6693", .driver_data = max6693 },
+	{ .name = "max6694", .driver_data = max6694 },
+	{ .name = "max6697", .driver_data = max6697 },
+	{ .name = "max6698", .driver_data = max6698 },
+	{ .name = "max6699", .driver_data = max6699 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, max6697_id);
drivers/hwmon/mc34vr500.c +2 -2
index 84458e4533d860..8cb9d5c09033f0 100644
@@ -235,8 +235,8 @@ static int mc34vr500_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id mc34vr500_id[] = {
-	{ "mc34vr500" },
-	{ },
+	{ .name = "mc34vr500" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, mc34vr500_id);
 
drivers/hwmon/mcp3021.c +2 -2
index bcddf6804d3abe..d6b0ebf27941f5 100644
@@ -177,8 +177,8 @@ static int mcp3021_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id mcp3021_id[] = {
-	{ "mcp3021", mcp3021 },
-	{ "mcp3221", mcp3221 },
+	{ .name = "mcp3021", .driver_data = mcp3021 },
+	{ .name = "mcp3221", .driver_data = mcp3221 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, mcp3021_id);
drivers/hwmon/nct6775-i2c.c +13 -13
index ba71d776a2911b..07783910c05882 100644
@@ -93,19 +93,19 @@ static const struct of_device_id __maybe_unused nct6775_i2c_of_match[] = {
 MODULE_DEVICE_TABLE(of, nct6775_i2c_of_match);
 
 static const struct i2c_device_id nct6775_i2c_id[] = {
-	{ "nct6106", nct6106 },
-	{ "nct6116", nct6116 },
-	{ "nct6775", nct6775 },
-	{ "nct6776", nct6776 },
-	{ "nct6779", nct6779 },
-	{ "nct6791", nct6791 },
-	{ "nct6792", nct6792 },
-	{ "nct6793", nct6793 },
-	{ "nct6795", nct6795 },
-	{ "nct6796", nct6796 },
-	{ "nct6797", nct6797 },
-	{ "nct6798", nct6798 },
-	{ "nct6799", nct6799 },
+	{ .name = "nct6106", .driver_data = nct6106 },
+	{ .name = "nct6116", .driver_data = nct6116 },
+	{ .name = "nct6775", .driver_data = nct6775 },
+	{ .name = "nct6776", .driver_data = nct6776 },
+	{ .name = "nct6779", .driver_data = nct6779 },
+	{ .name = "nct6791", .driver_data = nct6791 },
+	{ .name = "nct6792", .driver_data = nct6792 },
+	{ .name = "nct6793", .driver_data = nct6793 },
+	{ .name = "nct6795", .driver_data = nct6795 },
+	{ .name = "nct6796", .driver_data = nct6796 },
+	{ .name = "nct6797", .driver_data = nct6797 },
+	{ .name = "nct6798", .driver_data = nct6798 },
+	{ .name = "nct6799", .driver_data = nct6799 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, nct6775_i2c_id);
drivers/hwmon/nct7802.c +1 -1
index 8c9351da12c6e7..9c3e169547a9a1 100644
@@ -1193,7 +1193,7 @@ static const unsigned short nct7802_address_list[] = {
 };
 
 static const struct i2c_device_id nct7802_idtable[] = {
-	{ "nct7802" },
+	{ .name = "nct7802" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, nct7802_idtable);
drivers/hwmon/nct7904.c +2 -2
index 2fa091720c79b1..976b8a008e4480 100644
@@ -1146,8 +1146,8 @@ static int nct7904_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id nct7904_id[] = {
-	{"nct7904"},
-	{}
+	{ .name = "nct7904" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, nct7904_id);
 
drivers/hwmon/pcf8591.c +1 -1
index 167d2fe4d5432c..c0220ebfd4b60d 100644
@@ -285,7 +285,7 @@ static int pcf8591_read_channel(struct device *dev, int channel)
 }
 
 static const struct i2c_device_id pcf8591_id[] = {
-	{ "pcf8591" },
+	{ .name = "pcf8591" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, pcf8591_id);
drivers/hwmon/pmbus/acbel-fsg032.c +2 -2
index 9f07fb4abaffd4..d283005d92ae74 100644
@@ -49,8 +49,8 @@ static void acbel_fsg032_init_debugfs(struct i2c_client *client)
 }
 
 static const struct i2c_device_id acbel_fsg032_id[] = {
-	{ "acbel_fsg032" },
-	{}
+	{ .name = "acbel_fsg032" },
+	{ }
 };
 
 static struct pmbus_driver_info acbel_fsg032_info = {
drivers/hwmon/pmbus/adm1266.c +1 -1
index 6f6ad7b20e9a90..360a7730b80701 100644
@@ -510,7 +510,7 @@ static const struct of_device_id adm1266_of_match[] = {
 MODULE_DEVICE_TABLE(of, adm1266_of_match);
 
 static const struct i2c_device_id adm1266_id[] = {
-	{ "adm1266" },
+	{ .name = "adm1266" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adm1266_id);
drivers/hwmon/pmbus/adm1275.c +10 -10
index 43baa5ded35e50..cf7790bef652dc 100644
@@ -478,16 +478,16 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg)
 }
 
 static const struct i2c_device_id adm1275_id[] = {
-	{ "adm1075", adm1075 },
-	{ "adm1272", adm1272 },
-	{ "adm1273", adm1273 },
-	{ "adm1275", adm1275 },
-	{ "adm1276", adm1276 },
-	{ "adm1278", adm1278 },
-	{ "adm1281", adm1281 },
-	{ "adm1293", adm1293 },
-	{ "adm1294", adm1294 },
-	{ "mc09c", sq24905c },
+	{ .name = "adm1075", .driver_data = adm1075 },
+	{ .name = "adm1272", .driver_data = adm1272 },
+	{ .name = "adm1273", .driver_data = adm1273 },
+	{ .name = "adm1275", .driver_data = adm1275 },
+	{ .name = "adm1276", .driver_data = adm1276 },
+	{ .name = "adm1278", .driver_data = adm1278 },
+	{ .name = "adm1281", .driver_data = adm1281 },
+	{ .name = "adm1293", .driver_data = adm1293 },
+	{ .name = "adm1294", .driver_data = adm1294 },
+	{ .name = "mc09c", .driver_data = sq24905c },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adm1275_id);
drivers/hwmon/pmbus/bel-pfe.c +3 -3
index 6499556f735b42..9e3dc9d29c5628 100644
@@ -106,9 +106,9 @@ static int pfe_pmbus_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id pfe_device_id[] = {
-	{"pfe1100", pfe1100},
-	{"pfe3000", pfe3000},
-	{}
+	{ .name = "pfe1100", .driver_data = pfe1100 },
+	{ .name = "pfe3000", .driver_data = pfe3000 },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, pfe_device_id);
drivers/hwmon/pmbus/bpa-rs600.c +3 -3
index 6c3875ba37a081..e364dcb59dd427 100644
@@ -147,9 +147,9 @@ static struct pmbus_driver_info bpa_rs600_info = {
 };
 
 static const struct i2c_device_id bpa_rs600_id[] = {
-	{ "bpa-rs600", bpa_rs600 },
-	{ "bpd-rs600", bpd_rs600 },
-	{},
+	{ .name = "bpa-rs600", .driver_data = bpa_rs600 },
+	{ .name = "bpd-rs600", .driver_data = bpd_rs600 },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, bpa_rs600_id);
 
drivers/hwmon/pmbus/crps.c +2 -2
index 164b33fed312f6..266ec89475190c 100644
@@ -10,8 +10,8 @@
 #include "pmbus.h"
 
 static const struct i2c_device_id crps_id[] = {
-	{ "intel_crps185" },
-	{}
+	{ .name = "intel_crps185" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, crps_id);
 
drivers/hwmon/pmbus/delta-ahe50dc-fan.c +1 -1
index 3850eaea75da2a..2df655b20ea57d 100644
@@ -103,7 +103,7 @@ static int ahe50dc_fan_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ahe50dc_fan_id[] = {
-	{ "ahe50dc_fan" },
+	{ .name = "ahe50dc_fan" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ahe50dc_fan_id);
drivers/hwmon/pmbus/dps920ab.c +2 -2
index 325111a955e616..0d2901c314c2b9 100644
@@ -191,8 +191,8 @@ static const struct of_device_id __maybe_unused dps920ab_of_match[] = {
 MODULE_DEVICE_TABLE(of, dps920ab_of_match);
 
 static const struct i2c_device_id dps920ab_device_id[] = {
-	{ "dps920ab" },
-	{}
+	{ .name = "dps920ab" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, dps920ab_device_id);
 
drivers/hwmon/pmbus/fsp-3y.c +2 -2
index cad4d233000365..44cf2db9364b93 100644
@@ -271,8 +271,8 @@ static int fsp3y_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id fsp3y_id[] = {
-	{"ym2151e", ym2151e},
-	{"yh5151e", yh5151e},
+	{ .name = "ym2151e", .driver_data = ym2151e },
+	{ .name = "yh5151e", .driver_data = yh5151e },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, fsp3y_id);
drivers/hwmon/pmbus/hac300s.c +2 -2
index a073db1cfe2e49..761e53890ebc4b 100644
@@ -112,8 +112,8 @@ static const struct of_device_id hac300s_of_match[] = {
 MODULE_DEVICE_TABLE(of, hac300s_of_match);
 
 static const struct i2c_device_id hac300s_id[] = {
-	{"hac300s", 0},
-	{}
+	{ .name = "hac300s" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, hac300s_id);
 
drivers/hwmon/pmbus/ibm-cffps.c +4 -4
index 6c7256d997f46b..aad94bcb9ceb5f 100644
@@ -472,10 +472,10 @@ static struct pmbus_platform_data ibm_cffps_pdata = {
 };
 
 static const struct i2c_device_id ibm_cffps_id[] = {
-	{ "ibm_cffps1", cffps1 },
-	{ "ibm_cffps2", cffps2 },
-	{ "ibm_cffps", cffps_unknown },
-	{}
+	{ .name = "ibm_cffps1", .driver_data = cffps1 },
+	{ .name = "ibm_cffps2", .driver_data = cffps2 },
+	{ .name = "ibm_cffps", .driver_data = cffps_unknown },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ibm_cffps_id);
 
drivers/hwmon/pmbus/ina233.c +2 -2
index 652087589c55a6..c72aa258b7c678 100644
@@ -168,8 +168,8 @@ static int ina233_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ina233_id[] = {
-	{"ina233", 0},
-	{}
+	{ .name = "ina233" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ina233_id);
 
drivers/hwmon/pmbus/inspur-ipsps.c +2 -2
index 074e0f164ee1c9..57c0fc16909cfb 100644
@@ -197,8 +197,8 @@ static int ipsps_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ipsps_id[] = {
-	{ "ipsps1" },
-	{}
+	{ .name = "ipsps1" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ipsps_id);
 
drivers/hwmon/pmbus/ir35221.c +2 -2
index 46d8f334d49a45..b2120fc76f4092 100644
@@ -126,8 +126,8 @@ static int ir35221_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ir35221_id[] = {
-	{"ir35221"},
-	{}
+	{ .name = "ir35221" },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, ir35221_id);
drivers/hwmon/pmbus/ir36021.c +2 -2
index 34ce15fc708bcd..0dce4c3f666f5a 100644
@@ -51,8 +51,8 @@ static int ir36021_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ir36021_id[] = {
-	{ "ir36021" },
-	{},
+	{ .name = "ir36021" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ir36021_id);
 
drivers/hwmon/pmbus/ir38064.c +5 -5
index 7b4188e8bf4830..47ce88e9d13a31 100644
@@ -53,11 +53,11 @@ static int ir38064_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ir38064_id[] = {
-	{"ir38060"},
-	{"ir38064"},
-	{"ir38164"},
-	{"ir38263"},
-	{}
+	{ .name = "ir38060" },
+	{ .name = "ir38064" },
+	{ .name = "ir38164" },
+	{ .name = "ir38263" },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, ir38064_id);
drivers/hwmon/pmbus/irps5401.c +2 -2
index 43674c64841d5c..1694b96d7abf97 100644
@@ -44,8 +44,8 @@ static int irps5401_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id irps5401_id[] = {
-	{"irps5401"},
-	{}
+	{ .name = "irps5401" },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, irps5401_id);
drivers/hwmon/pmbus/isl68137.c +48 -48

102 lines not on this page · raw message

drivers/hwmon/pmbus/lm25066.c +5 -5
index dd7275a67a0abe..0f7df7e2c9c5ba 100644
@@ -442,11 +442,11 @@ static const struct regulator_desc lm25066_reg_desc[] = {
 #endif
 
 static const struct i2c_device_id lm25066_id[] = {
-	{"lm25056", lm25056},
-	{"lm25066", lm25066},
-	{"lm5064", lm5064},
-	{"lm5066", lm5066},
-	{"lm5066i", lm5066i},
+	{ .name = "lm25056", .driver_data = lm25056 },
+	{ .name = "lm25066", .driver_data = lm25066 },
+	{ .name = "lm5064", .driver_data = lm5064 },
+	{ .name = "lm5066", .driver_data = lm5066 },
+	{ .name = "lm5066i", .driver_data = lm5066i },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, lm25066_id);
drivers/hwmon/pmbus/lt7182s.c +2 -2
index 9d6d50f39bd653..f8971a786f25aa 100644
@@ -168,8 +168,8 @@ static int lt7182s_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id lt7182s_id[] = {
-	{ "lt7182s" },
-	{}
+	{ .name = "lt7182s" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, lt7182s_id);
 
drivers/hwmon/pmbus/ltc2978.c +30 -30

66 lines not on this page · raw message

drivers/hwmon/pmbus/ltc3815.c +1 -1
index 824c16a75e2c01..0219d03adb0377 100644
@@ -143,7 +143,7 @@ static int ltc3815_write_word_data(struct i2c_client *client, int page,
 }
 
 static const struct i2c_device_id ltc3815_id[] = {
-	{"ltc3815"},
+	{ .name = "ltc3815" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ltc3815_id);
drivers/hwmon/pmbus/max15301.c +4 -4
index d5810b88ea8d8d..4c36f1ea27ee65 100644
@@ -23,10 +23,10 @@
 #include "pmbus.h"
 
 static const struct i2c_device_id max15301_id[] = {
-	{ "bmr461" },
-	{ "max15301" },
-	{ "max15303" },
-	{}
+	{ .name = "bmr461" },
+	{ .name = "max15301" },
+	{ .name = "max15303" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, max15301_id);
 
drivers/hwmon/pmbus/max16064.c +2 -2
index eb84915c2a83de..351a1f53599945 100644
@@ -91,8 +91,8 @@ static int max16064_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id max16064_id[] = {
-	{"max16064"},
-	{}
+	{ .name = "max16064" },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, max16064_id);
drivers/hwmon/pmbus/max16601.c +5 -5
index 36dc13424d9290..3dd1f6fd003b89 100644
@@ -263,11 +263,11 @@ static void max16601_remove(void *_data)
 }
 
 static const struct i2c_device_id max16601_id[] = {
-	{"max16508", max16508},
-	{"max16600", max16600},
-	{"max16601", max16601},
-	{"max16602", max16602},
-	{}
+	{ .name = "max16508", .driver_data = max16508 },
+	{ .name = "max16600", .driver_data = max16600 },
+	{ .name = "max16601", .driver_data = max16601 },
+	{ .name = "max16602", .driver_data = max16602 },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, max16601_id);
 
drivers/hwmon/pmbus/max17616.c +1 -1
index 1d4a0ddb95bb6e..744fa5aefe9388 100644
@@ -46,7 +46,7 @@ static int max17616_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id max17616_id[] = {
-	{ "max17616" },
+	{ .name = "max17616" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, max17616_id);
drivers/hwmon/pmbus/max20730.c +5 -5
index fe03164788dfa2..4031f894e6ae7e 100644
@@ -751,11 +751,11 @@ static int max20730_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id max20730_id[] = {
-	{ "max20710", max20710 },
-	{ "max20730", max20730 },
-	{ "max20734", max20734 },
-	{ "max20743", max20743 },
-	{ },
+	{ .name = "max20710", .driver_data = max20710 },
+	{ .name = "max20730", .driver_data = max20730 },
+	{ .name = "max20734", .driver_data = max20734 },
+	{ .name = "max20743", .driver_data = max20743 },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, max20730_id);
drivers/hwmon/pmbus/max20751.c +2 -2
index ac8c431221338b..e85676433dca11 100644
@@ -32,8 +32,8 @@ static int max20751_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id max20751_id[] = {
-	{"max20751"},
-	{}
+	{ .name = "max20751" },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, max20751_id);
drivers/hwmon/pmbus/max31785.c +4 -4
index 3caa76bcbeb5ea..bdcce810a4792c 100644
@@ -447,10 +447,10 @@ static int max31785_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id max31785_id[] = {
-	{ "max31785" },
-	{ "max31785a" },
-	{ "max31785b" },
-	{ },
+	{ .name = "max31785" },
+	{ .name = "max31785a" },
+	{ .name = "max31785b" },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, max31785_id);
drivers/hwmon/pmbus/max34440.c +9 -9
index cc96bb22f8f5a0..4525b9fc562674 100644
@@ -644,15 +644,15 @@ static int max34440_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id max34440_id[] = {
-	{"adpm12160", adpm12160},
-	{"adpm12200", adpm12200},
-	{"max34440", max34440},
-	{"max34441", max34441},
-	{"max34446", max34446},
-	{"max34451", max34451},
-	{"max34460", max34460},
-	{"max34461", max34461},
-	{}
+	{ .name = "adpm12160", .driver_data = adpm12160 },
+	{ .name = "adpm12200", .driver_data = adpm12200 },
+	{ .name = "max34440", .driver_data = max34440 },
+	{ .name = "max34441", .driver_data = max34441 },
+	{ .name = "max34446", .driver_data = max34446 },
+	{ .name = "max34451", .driver_data = max34451 },
+	{ .name = "max34460", .driver_data = max34460 },
+	{ .name = "max34461", .driver_data = max34461 },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, max34440_id);
 
drivers/hwmon/pmbus/max8688.c +1 -1
index b3a2a7492bbfcf..212b28fa4bf226 100644
@@ -171,7 +171,7 @@ static int max8688_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id max8688_id[] = {
-	{"max8688"},
+	{ .name = "max8688" },
 	{ }
 };
 
drivers/hwmon/pmbus/mp2856.c +3 -3
index e83c70a3583f80..3d6621e36fd398 100644
@@ -54,9 +54,9 @@ static const int mp2856_max_phases[][MP2856_PAGE_NUM] = {
 };
 
 static const struct i2c_device_id mp2856_id[] = {
-	{"mp2856", mp2856},
-	{"mp2857", mp2857},
-	{}
+	{ .name = "mp2856", .driver_data = mp2856 },
+	{ .name = "mp2857", .driver_data = mp2857 },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, mp2856_id);
drivers/hwmon/pmbus/mp2888.c +2 -2
index 772a623ca7d0a1..c5f35daa3fe11e 100644
@@ -378,8 +378,8 @@ static int mp2888_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id mp2888_id[] = {
-	{"mp2888"},
-	{}
+	{ .name = "mp2888" },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, mp2888_id);
drivers/hwmon/pmbus/mp2891.c +1 -1
index f8f4c91ec23ccd..316c1fc0d6ccf1 100644
@@ -572,7 +572,7 @@ static int mp2891_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id mp2891_id[] = {
-	{ "mp2891" },
+	{ .name = "mp2891" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, mp2891_id);
drivers/hwmon/pmbus/mp2925.c +3 -3
index ad094842cf2d73..0a58b1ffd79108 100644
@@ -305,9 +305,9 @@ static int mp2925_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id mp2925_id[] = {
-	{"mp2925"},
-	{"mp2929"},
-	{}
+	{ .name = "mp2925" },
+	{ .name = "mp2929" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, mp2925_id);
 
drivers/hwmon/pmbus/mp29502.c +2 -2
index 7241373f155770..afc5e8c07e2598 100644
@@ -642,8 +642,8 @@ static int mp29502_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id mp29502_id[] = {
-	{"mp29502", 0},
-	{}
+	{ .name = "mp29502", .driver_data = 0 },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, mp29502_id);
 
drivers/hwmon/pmbus/mp2975.c +4 -4
index d0bc47b12cb07d..dca7e2fbcb441d 100644
@@ -1082,10 +1082,10 @@ static const struct of_device_id mp2975_of_match[] = {
 MODULE_DEVICE_TABLE(of, mp2975_of_match);
 
 static const struct i2c_device_id mp2975_id[] = {
-	{"mp2971", (kernel_ulong_t)&mp2975_ddinfo[mp2971]},
-	{"mp2973", (kernel_ulong_t)&mp2975_ddinfo[mp2973]},
-	{"mp2975", (kernel_ulong_t)&mp2975_ddinfo[mp2975]},
-	{}
+	{ .name = "mp2971", .driver_data = (kernel_ulong_t)&mp2975_ddinfo[mp2971] },
+	{ .name = "mp2973", .driver_data = (kernel_ulong_t)&mp2975_ddinfo[mp2973] },
+	{ .name = "mp2975", .driver_data = (kernel_ulong_t)&mp2975_ddinfo[mp2975] },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, mp2975_id);
 
drivers/hwmon/pmbus/mp2993.c +1 -1
index 81c84fc8ed47d2..3a6a6c55a1f17d 100644
@@ -233,7 +233,7 @@ static int mp2993_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id mp2993_id[] = {
-	{ "mp2993" },
+	{ .name = "mp2993" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, mp2993_id);
drivers/hwmon/pmbus/mp5920.c +1 -1
index 319ae2721bcf45..b803f3ddf8ea17 100644
@@ -66,7 +66,7 @@ static const struct of_device_id mp5920_of_match[] = {
 MODULE_DEVICE_TABLE(of, mp5920_of_match);
 
 static const struct i2c_device_id mp5920_id[] = {
-	{ "mp5920" },
+	{ .name = "mp5920" },
 	{ }
 };
 
drivers/hwmon/pmbus/mp5926.c +2 -2
index f0d1b30c70134d..a40647472b1601 100644
@@ -157,8 +157,8 @@ static int mp5926_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id mp5926_id[] = {
-	{ "mp5926", 0 },
-	{}
+	{ .name = "mp5926", .driver_data = 0 },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, mp5926_id);
 
drivers/hwmon/pmbus/mp5990.c +2 -2
index 9a4ee79712cfcf..f8a5d1b42ff7ab 100644
@@ -148,8 +148,8 @@ static struct pmbus_driver_info mp5998_info = {
 };
 
 static const struct i2c_device_id mp5990_id[] = {
-	{"mp5990", mp5990},
-	{"mp5998", mp5998},
+	{ .name = "mp5990", .driver_data = mp5990 },
+	{ .name = "mp5998", .driver_data = mp5998 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, mp5990_id);
drivers/hwmon/pmbus/mp9941.c +1 -1
index 42ca6748777afd..d9049d326c809d 100644
@@ -291,7 +291,7 @@ static int mp9941_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id mp9941_id[] = {
-	{ "mp9941" },
+	{ .name = "mp9941" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, mp9941_id);
drivers/hwmon/pmbus/mp9945.c +2 -2
index 34822e0de8128f..199480d855157f 100644
@@ -215,8 +215,8 @@ static int mp9945_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id mp9945_id[] = {
-	{"mp9945"},
-	{}
+	{ .name = "mp9945" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, mp9945_id);
 
drivers/hwmon/pmbus/mpq7932.c +3 -3
index 8f10e37a7a7677..f49610adff89c4 100644
@@ -145,9 +145,9 @@ static const struct of_device_id mpq7932_of_match[] = {
 MODULE_DEVICE_TABLE(of, mpq7932_of_match);
 
 static const struct i2c_device_id mpq7932_id[] = {
-	{ "mpq2286", },
-	{ "mpq7932", },
-	{ },
+	{ .name = "mpq2286" },
+	{ .name = "mpq7932" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, mpq7932_id);
 
drivers/hwmon/pmbus/mpq8785.c +5 -5
index 87bd039c77b9b3..bbde55028290a9 100644
@@ -110,11 +110,11 @@ static struct pmbus_driver_info mpq8785_info = {
 };
 
 static const struct i2c_device_id mpq8785_id[] = {
-	{ "mpm3695", mpm3695 },
-	{ "mpm3695-25", mpm3695_25 },
-	{ "mpm82504", mpm82504 },
-	{ "mpq8785", mpq8785 },
-	{ },
+	{ .name = "mpm3695", .driver_data = mpm3695 },
+	{ .name = "mpm3695-25", .driver_data = mpm3695_25 },
+	{ .name = "mpm82504", .driver_data = mpm82504 },
+	{ .name = "mpq8785", .driver_data = mpq8785 },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, mpq8785_id);
 
drivers/hwmon/pmbus/pim4328.c +9 -9
index aa98284bbdd847..9056dc387e878f 100644
@@ -39,15 +39,15 @@ struct pim4328_data {
 #define PIM4328_MFR_READ_STATUS		0xd0
 
 static const struct i2c_device_id pim4328_id[] = {
-	{"bmr455", pim4328},
-	{"pim4006", pim4006},
-	{"pim4106", pim4006},
-	{"pim4206", pim4006},
-	{"pim4306", pim4006},
-	{"pim4328", pim4328},
-	{"pim4406", pim4006},
-	{"pim4820", pim4820},
-	{}
+	{ .name = "bmr455", .driver_data = pim4328 },
+	{ .name = "pim4006", .driver_data = pim4006 },
+	{ .name = "pim4106", .driver_data = pim4006 },
+	{ .name = "pim4206", .driver_data = pim4006 },
+	{ .name = "pim4306", .driver_data = pim4006 },
+	{ .name = "pim4328", .driver_data = pim4328 },
+	{ .name = "pim4406", .driver_data = pim4006 },
+	{ .name = "pim4820", .driver_data = pim4820 },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, pim4328_id);
 
drivers/hwmon/pmbus/pli1209bc.c +2 -2
index 569b61dc1a32a6..d5ab085a227303 100644
@@ -117,8 +117,8 @@ static int pli1209bc_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id pli1209bc_id[] = {
-	{"pli1209bc"},
-	{}
+	{ .name = "pli1209bc" },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, pli1209bc_id);
drivers/hwmon/pmbus/pm6764tr.c +2 -2
index c96c0aecb920a8..613654b15b4a1f 100644
@@ -48,8 +48,8 @@ static int pm6764tr_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id pm6764tr_id[] = {
-	{"pm6764tr"},
-	{}
+	{ .name = "pm6764tr" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, pm6764tr_id);
 
drivers/hwmon/pmbus/pmbus.c +30 -30

66 lines not on this page · raw message

drivers/hwmon/pmbus/pxe1610.c +4 -4
index 24c1f961c76689..6ba2b3e0e565b7 100644
@@ -130,10 +130,10 @@ static int pxe1610_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id pxe1610_id[] = {
-	{"pxe1610"},
-	{"pxe1110"},
-	{"pxm1310"},
-	{}
+	{ .name = "pxe1610" },
+	{ .name = "pxe1110" },
+	{ .name = "pxm1310" },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, pxe1610_id);
drivers/hwmon/pmbus/q54sj108a2.c +4 -4
index a368cfa9d45ac2..ecac405d753620 100644
@@ -270,10 +270,10 @@ static const struct file_operations q54sj108a2_fops = {
 };
 
 static const struct i2c_device_id q54sj108a2_id[] = {
-	{ "q54sj108a2", q54sj108a2 },
-	{ "q54sn120a1", q54sj108a2 },
-	{ "q54sw120a7", q54sj108a2 },
-	{ },
+	{ .name = "q54sj108a2", .driver_data = q54sj108a2 },
+	{ .name = "q54sn120a1", .driver_data = q54sj108a2 },
+	{ .name = "q54sw120a7", .driver_data = q54sj108a2 },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, q54sj108a2_id);
drivers/hwmon/pmbus/stef48h28.c +2 -2
index 4bde2215697cba..8e48dd3ba74bf3 100644
@@ -48,8 +48,8 @@ static int stef48h28_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id stef48h28_id[] = {
-	{"stef48h28"},
-	{}
+	{ .name = "stef48h28" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, stef48h28_id);
 
drivers/hwmon/pmbus/stpddc60.c +3 -3
index 5cb905ed8ae5f0..b5ce7f975eea49 100644
@@ -18,9 +18,9 @@
 #define STPDDC60_MFR_UV_LIMIT_OFFSET	0xe6
 
 static const struct i2c_device_id stpddc60_id[] = {
-	{"stpddc60"},
-	{"bmr481"},
-	{}
+	{ .name = "stpddc60" },
+	{ .name = "bmr481" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, stpddc60_id);
 
drivers/hwmon/pmbus/tda38640.c +2 -2
index d902d39f49f4d7..8039266333700c 100644
@@ -195,8 +195,8 @@ static int tda38640_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id tda38640_id[] = {
-	{"tda38640"},
-	{}
+	{ .name = "tda38640" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, tda38640_id);
 
drivers/hwmon/pmbus/tps25990.c +2 -2
index 05c6288ecafccb..9d318e6509abf6 100644
@@ -387,8 +387,8 @@ static const struct pmbus_driver_info tps25990_base_info = {
 };
 
 static const struct i2c_device_id tps25990_i2c_id[] = {
-	{ "tps25990" },
-	{}
+	{ .name = "tps25990" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, tps25990_i2c_id);
 
drivers/hwmon/pmbus/tps40422.c +2 -2
index 7c9fedaa068c0b..f7be075dc70702 100644
@@ -31,8 +31,8 @@ static int tps40422_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id tps40422_id[] = {
-	{"tps40422"},
-	{}
+	{ .name = "tps40422" },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, tps40422_id);
drivers/hwmon/pmbus/tps53679.c +9 -9
index 94258e8cfd903b..31e54608b3c9c0 100644
@@ -291,15 +291,15 @@ static int tps53679_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id tps53679_id[] = {
-	{"bmr474", tps53676},
-	{"tps53647", tps53647},
-	{"tps53667", tps53667},
-	{"tps53676", tps53676},
-	{"tps53679", tps53679},
-	{"tps53681", tps53681},
-	{"tps53685", tps53685},
-	{"tps53688", tps53688},
-	{}
+	{ .name = "bmr474", .driver_data = tps53676 },
+	{ .name = "tps53647", .driver_data = tps53647 },
+	{ .name = "tps53667", .driver_data = tps53667 },
+	{ .name = "tps53676", .driver_data = tps53676 },
+	{ .name = "tps53679", .driver_data = tps53679 },
+	{ .name = "tps53681", .driver_data = tps53681 },
+	{ .name = "tps53685", .driver_data = tps53685 },
+	{ .name = "tps53688", .driver_data = tps53688 },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, tps53679_id);
drivers/hwmon/pmbus/tps546d24.c +2 -2
index 44d7a6df1dbdfc..4222ff355e02b4 100644
@@ -42,8 +42,8 @@ static int tps546d24_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id tps546d24_id[] = {
-	{"tps546d24"},
-	{}
+	{ .name = "tps546d24" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, tps546d24_id);
 
drivers/hwmon/pmbus/ucd9000.c +8 -8
index 9b5d34a110ba5e..f76c2913c9caec 100644
@@ -143,14 +143,14 @@ static int ucd9000_read_byte_data(struct i2c_client *client, int page, int reg)
 }
 
 static const struct i2c_device_id ucd9000_id[] = {
-	{"ucd9000", ucd9000},
-	{"ucd90120", ucd90120},
-	{"ucd90124", ucd90124},
-	{"ucd90160", ucd90160},
-	{"ucd90320", ucd90320},
-	{"ucd9090", ucd9090},
-	{"ucd90910", ucd90910},
-	{}
+	{ .name = "ucd9000", .driver_data = ucd9000 },
+	{ .name = "ucd90120", .driver_data = ucd90120 },
+	{ .name = "ucd90124", .driver_data = ucd90124 },
+	{ .name = "ucd90160", .driver_data = ucd90160 },
+	{ .name = "ucd90320", .driver_data = ucd90320 },
+	{ .name = "ucd9090", .driver_data = ucd9090 },
+	{ .name = "ucd90910", .driver_data = ucd90910 },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ucd9000_id);
 
drivers/hwmon/pmbus/ucd9200.c +9 -9
index f68adaf4a110e0..5e07bba111a162 100644
@@ -22,15 +22,15 @@ enum chips { ucd9200, ucd9220, ucd9222, ucd9224, ucd9240, ucd9244, ucd9246,
 	     ucd9248 };
 
 static const struct i2c_device_id ucd9200_id[] = {
-	{"ucd9200", ucd9200},
-	{"ucd9220", ucd9220},
-	{"ucd9222", ucd9222},
-	{"ucd9224", ucd9224},
-	{"ucd9240", ucd9240},
-	{"ucd9244", ucd9244},
-	{"ucd9246", ucd9246},
-	{"ucd9248", ucd9248},
-	{}
+	{ .name = "ucd9200", .driver_data = ucd9200 },
+	{ .name = "ucd9220", .driver_data = ucd9220 },
+	{ .name = "ucd9222", .driver_data = ucd9222 },
+	{ .name = "ucd9224", .driver_data = ucd9224 },
+	{ .name = "ucd9240", .driver_data = ucd9240 },
+	{ .name = "ucd9244", .driver_data = ucd9244 },
+	{ .name = "ucd9246", .driver_data = ucd9246 },
+	{ .name = "ucd9248", .driver_data = ucd9248 },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ucd9200_id);
 
drivers/hwmon/pmbus/xdp710.c +1 -1
index 660bbfe16e1e9d..494dbe45ebc6b5 100644
@@ -110,7 +110,7 @@ static const struct of_device_id xdp710_of_match[] = {
 };
 
 static const struct i2c_device_id xdp710_id[] = {
-	{"xdp710"},
+	{ .name = "xdp710" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, xdp710_id);
drivers/hwmon/pmbus/xdp720.c +2 -2
index 8729a771f21667..60491e9217bfb9 100644
@@ -106,8 +106,8 @@ static const struct of_device_id xdp720_of_match[] = {
 MODULE_DEVICE_TABLE(of, xdp720_of_match);
 
 static const struct i2c_device_id xdp720_id[] = {
-	{ "xdp720" },
-	{}
+	{ .name = "xdp720" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, xdp720_id);
 
drivers/hwmon/pmbus/xdpe12284.c +4 -4
index f3aa6339d60d0f..ed93e17ce8d512 100644
@@ -164,10 +164,10 @@ static int xdpe122_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id xdpe122_id[] = {
-	{"xdpe11280"},
-	{"xdpe12254"},
-	{"xdpe12284"},
-	{}
+	{ .name = "xdpe11280" },
+	{ .name = "xdpe12254" },
+	{ .name = "xdpe12284" },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, xdpe122_id);
drivers/hwmon/pmbus/xdpe152c4.c +3 -3
index 67a3d5fe1dafad..b557d2971d5f24 100644
@@ -44,9 +44,9 @@ static int xdpe152_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id xdpe152_id[] = {
-	{"xdpe152c4"},
-	{"xdpe15284"},
-	{}
+	{ .name = "xdpe152c4" },
+	{ .name = "xdpe15284" },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, xdpe152_id);
drivers/hwmon/pmbus/xdpe1a2g7b.c +3 -3
index 1755e3522ede54..971e7b73752ea1 100644
@@ -87,9 +87,9 @@ static int xdpe1a2g7b_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id xdpe1a2g7b_id[] = {
-	{ "xdpe1a2g5b" },
-	{ "xdpe1a2g7b" },
-	{}
+	{ .name = "xdpe1a2g5b" },
+	{ .name = "xdpe1a2g7b" },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, xdpe1a2g7b_id);
drivers/hwmon/pmbus/zl6100.c +22 -22

50 lines not on this page · raw message

drivers/hwmon/powr1220.c +2 -2
index 06a2c56016d117..6e211601ea26b7 100644
@@ -306,8 +306,8 @@ static int powr1220_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id powr1220_ids[] = {
-	{ "powr1014", powr1014, },
-	{ "powr1220", powr1220, },
+	{ .name = "powr1014", .driver_data = powr1014 },
+	{ .name = "powr1220", .driver_data = powr1220 },
 	{ }
 };
 
drivers/hwmon/pt5161l.c +2 -2
index 89d4da8aa4c093..2b408a69b085c1 100644
@@ -617,8 +617,8 @@ static const struct acpi_device_id __maybe_unused pt5161l_acpi_match[] = {
 MODULE_DEVICE_TABLE(acpi, pt5161l_acpi_match);
 
 static const struct i2c_device_id pt5161l_id[] = {
-	{ "pt5161l" },
-	{}
+	{ .name = "pt5161l" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, pt5161l_id);
 
drivers/hwmon/sbtsi_temp.c +2 -2
index c5b2488c4c7f74..c28f8625cd3a49 100644
@@ -221,8 +221,8 @@ static int sbtsi_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id sbtsi_id[] = {
-	{"sbtsi"},
-	{}
+	{ .name = "sbtsi" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, sbtsi_id);
 
drivers/hwmon/sg2042-mcu.c +1 -1
index 105131c4acf787..591f5f572fe4ce 100644
@@ -333,7 +333,7 @@ static int sg2042_mcu_i2c_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id sg2042_mcu_id[] = {
-	{ "sg2042-hwmon-mcu" },
+	{ .name = "sg2042-hwmon-mcu" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, sg2042_mcu_id);
drivers/hwmon/sht21.c +3 -3
index 627d35070a420a..085492669eeb99 100644
@@ -275,9 +275,9 @@ static int sht21_probe(struct i2c_client *client)
 
 /* Device ID table */
 static const struct i2c_device_id sht21_id[] = {
-	{ "sht20" },
-	{ "sht21" },
-	{ "sht25" },
+	{ .name = "sht20" },
+	{ .name = "sht21" },
+	{ .name = "sht25" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, sht21_id);
drivers/hwmon/sht3x.c +4 -4
index 08306ccb6d0bef..c2f6b73aa7f34a 100644
@@ -931,10 +931,10 @@ static int sht3x_probe(struct i2c_client *client)
 
 /* device ID table */
 static const struct i2c_device_id sht3x_ids[] = {
-	{"sht3x", sht3x},
-	{"sts3x", sts3x},
-	{"sht85", sht3x},
-	{}
+	{ .name = "sht3x", .driver_data = sht3x },
+	{ .name = "sts3x", .driver_data = sts3x },
+	{ .name = "sht85", .driver_data = sht3x },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, sht3x_ids);
drivers/hwmon/sht4x.c +2 -2
index 5abe1227e109ed..9cace0e8acdabc 100644
@@ -424,8 +424,8 @@ static int sht4x_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id sht4x_id[] = {
-	{ "sht4x" },
-	{ },
+	{ .name = "sht4x" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, sht4x_id);
 
drivers/hwmon/shtc1.c +3 -3
index 2ac906e8e17332..362a73cf661b20 100644
@@ -257,9 +257,9 @@ static int shtc1_probe(struct i2c_client *client)
 
 /* device ID table */
 static const struct i2c_device_id shtc1_id[] = {
-	{ "shtc1", shtc1 },
-	{ "shtw1", shtc1 },
-	{ "shtc3", shtc3 },
+	{ .name = "shtc1", .driver_data = shtc1 },
+	{ .name = "shtw1", .driver_data = shtc1 },
+	{ .name = "shtc3", .driver_data = shtc3 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, shtc1_id);
drivers/hwmon/smsc47m192.c +1 -1
index 21103af4e1395a..1429b66e09b07d 100644
@@ -618,7 +618,7 @@ static int smsc47m192_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id smsc47m192_id[] = {
-	{ "smsc47m192" },
+	{ .name = "smsc47m192" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, smsc47m192_id);
drivers/hwmon/spd5118.c +1 -1
index 5da44571b6a0ce..cc40661cab211a 100644
@@ -746,7 +746,7 @@ static int spd5118_i2c_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id spd5118_i2c_id[] = {
-	{ "spd5118" },
+	{ .name = "spd5118" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, spd5118_i2c_id);
drivers/hwmon/stts751.c +1 -1
index f9e8b2869164a3..ce23681f79810a 100644
@@ -72,7 +72,7 @@ static const int stts751_intervals[] = {
 };
 
 static const struct i2c_device_id stts751_id[] = {
-	{ "stts751" },
+	{ .name = "stts751" },
 	{ }
 };
 
drivers/hwmon/tc654.c +3 -3
index 39fe5836f237f2..4b22e305b203ea 100644
@@ -550,9 +550,9 @@ static int tc654_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id tc654_id[] = {
-	{"tc654"},
-	{"tc655"},
-	{}
+	{ .name = "tc654" },
+	{ .name = "tc655" },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(i2c, tc654_id);
drivers/hwmon/tc74.c +2 -2
index 7fb7b50ad1adbf..e9113519be5355 100644
@@ -151,8 +151,8 @@ static int tc74_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id tc74_id[] = {
-	{ "tc74" },
-	{}
+	{ .name = "tc74" },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, tc74_id);
 
drivers/hwmon/thmc50.c +2 -2
index 0cbdb91698b1f7..b385ef64af7542 100644
@@ -407,8 +407,8 @@ static int thmc50_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id thmc50_id[] = {
-	{ "adm1022", adm1022 },
-	{ "thmc50", thmc50 },
+	{ .name = "adm1022", .driver_data = adm1022 },
+	{ .name = "thmc50", .driver_data = thmc50 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, thmc50_id);
drivers/hwmon/tmp102.c +1 -1
index 3aa1a3fbeaa92d..500286676174ee 100644
@@ -395,7 +395,7 @@ static int tmp102_resume(struct device *dev)
 static DEFINE_SIMPLE_DEV_PM_OPS(tmp102_dev_pm_ops, tmp102_suspend, tmp102_resume);
 
 static const struct i2c_device_id tmp102_id[] = {
-	{ "tmp102" },
+	{ .name = "tmp102" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, tmp102_id);
drivers/hwmon/tmp103.c +1 -1
index 221bba8a215d83..f13d2476757514 100644
@@ -194,7 +194,7 @@ static int tmp103_resume(struct device *dev)
 static DEFINE_SIMPLE_DEV_PM_OPS(tmp103_dev_pm_ops, tmp103_suspend, tmp103_resume);
 
 static const struct i2c_device_id tmp103_id[] = {
-	{ "tmp103" },
+	{ .name = "tmp103" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, tmp103_id);
drivers/hwmon/tmp108.c +4 -4
index 3ea5f6485744d7..1c4a58855e2d27 100644
@@ -537,10 +537,10 @@ static int tmp108_resume(struct device *dev)
 static DEFINE_SIMPLE_DEV_PM_OPS(tmp108_dev_pm_ops, tmp108_suspend, tmp108_resume);
 
 static const struct i2c_device_id tmp108_i2c_ids[] = {
-	{ "p3t1035", (unsigned long)&p3t1035_data },
-	{ "p3t1085", (unsigned long)&tmp108_data },
-	{ "tmp108", (unsigned long)&tmp108_data },
-	{}
+	{ .name = "p3t1035", .driver_data = (unsigned long)&p3t1035_data },
+	{ .name = "p3t1085", .driver_data = (unsigned long)&tmp108_data },
+	{ .name = "tmp108", .driver_data = (unsigned long)&tmp108_data },
+	{ }
 };
 MODULE_DEVICE_TABLE(i2c, tmp108_i2c_ids);
 
drivers/hwmon/tmp401.c +5 -5
index 07f596581c6eb7..a09225a87355dd 100644
@@ -90,11 +90,11 @@ static const u8 TMP432_STATUS_REG[] = {
  */
 
 static const struct i2c_device_id tmp401_id[] = {
-	{ "tmp401", tmp401 },
-	{ "tmp411", tmp411 },
-	{ "tmp431", tmp431 },
-	{ "tmp432", tmp432 },
-	{ "tmp435", tmp435 },
+	{ .name = "tmp401", .driver_data = tmp401 },
+	{ .name = "tmp411", .driver_data = tmp411 },
+	{ .name = "tmp431", .driver_data = tmp431 },
+	{ .name = "tmp432", .driver_data = tmp432 },
+	{ .name = "tmp435", .driver_data = tmp435 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, tmp401_id);
drivers/hwmon/tmp421.c +5 -5
index 2ea9d3e9553db8..ed00ccfdd7b3ee 100644
@@ -56,11 +56,11 @@ static const u8 TMP421_TEMP_LSB[MAX_CHANNELS]	= { 0x10, 0x11, 0x12, 0x13 };
 #define TMP442_DEVICE_ID			0x42
 
 static const struct i2c_device_id tmp421_id[] = {
-	{ "tmp421", 2 },
-	{ "tmp422", 3 },
-	{ "tmp423", 4 },
-	{ "tmp441", 2 },
-	{ "tmp442", 3 },
+	{ .name = "tmp421", .driver_data = 2 },
+	{ .name = "tmp422", .driver_data = 3 },
+	{ .name = "tmp423", .driver_data = 4 },
+	{ .name = "tmp441", .driver_data = 2 },
+	{ .name = "tmp442", .driver_data = 3 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, tmp421_id);
drivers/hwmon/tmp464.c +2 -2
index 98f2576d94c670..c3e031044d1e71 100644
@@ -65,8 +65,8 @@ static const u8 TMP464_THERM2_LIMIT[MAX_CHANNELS] = {
 #define TMP468_DEVICE_ID			0x0468
 
 static const struct i2c_device_id tmp464_id[] = {
-	{ "tmp464", TMP464_NUM_CHANNELS },
-	{ "tmp468", TMP468_NUM_CHANNELS },
+	{ .name = "tmp464", .driver_data = TMP464_NUM_CHANNELS },
+	{ .name = "tmp468", .driver_data = TMP468_NUM_CHANNELS },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, tmp464_id);
drivers/hwmon/tmp513.c +2 -2
index 5acbfd7d088dd5..b160aa045f89dd 100644
@@ -611,8 +611,8 @@ static int tmp51x_init(struct tmp51x_data *data)
 }
 
 static const struct i2c_device_id tmp51x_id[] = {
-	{ "tmp512", TMP512_MAX_CHANNELS },
-	{ "tmp513", TMP513_MAX_CHANNELS },
+	{ .name = "tmp512", .driver_data = TMP512_MAX_CHANNELS },
+	{ .name = "tmp513", .driver_data = TMP513_MAX_CHANNELS },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, tmp51x_id);
drivers/hwmon/w83773g.c +1 -1
index 401a28f55f931f..54224dac10aef6 100644
@@ -34,7 +34,7 @@ static const u8 W83773_OFFSET_MSB[2] = { 0x11, 0x15 };
 
 /* this is the number of sensors in the device */
 static const struct i2c_device_id w83773_id[] = {
-	{ "w83773g" },
+	{ .name = "w83773g" },
 	{ }
 };
 
drivers/hwmon/w83781d.c +4 -4
index f664c2152a6dee..c40f84e5346964 100644
@@ -1559,10 +1559,10 @@ static struct w83781d_data *w83781d_update_device(struct device *dev)
 }
 
 static const struct i2c_device_id w83781d_ids[] = {
-	{ "w83781d", w83781d, },
-	{ "w83782d", w83782d, },
-	{ "w83783s", w83783s, },
-	{ "as99127f", as99127f },
+	{ .name = "w83781d", .driver_data = w83781d },
+	{ .name = "w83782d", .driver_data = w83782d },
+	{ .name = "w83783s", .driver_data = w83783s },
+	{ .name = "as99127f", .driver_data = as99127f },
 	{ /* LIST END */ }
 };
 MODULE_DEVICE_TABLE(i2c, w83781d_ids);
drivers/hwmon/w83791d.c +1 -1
index 996e36951f9dad..4a777430af5cd4 100644
@@ -333,7 +333,7 @@ static void w83791d_print_debug(struct w83791d_data *data, struct device *dev);
 static void w83791d_init_client(struct i2c_client *client);
 
 static const struct i2c_device_id w83791d_id[] = {
-	{ "w83791d" },
+	{ .name = "w83791d" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, w83791d_id);
drivers/hwmon/w83792d.c +1 -1
index b0b5f60eea53bc..f715c79389a565 100644
@@ -296,7 +296,7 @@ static void w83792d_print_debug(struct w83792d_data *data, struct device *dev);
 static void w83792d_init_client(struct i2c_client *client);
 
 static const struct i2c_device_id w83792d_id[] = {
-	{ "w83792d" },
+	{ .name = "w83792d" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, w83792d_id);
drivers/hwmon/w83793.c +1 -1
index 8726c5fe8a952e..a548586369e1db 100644
@@ -291,7 +291,7 @@ static void w83793_update_nonvolatile(struct device *dev);
 static struct w83793_data *w83793_update_device(struct device *dev);
 
 static const struct i2c_device_id w83793_id[] = {
-	{ "w83793" },
+	{ .name = "w83793" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, w83793_id);
drivers/hwmon/w83795.c +2 -2
index 5174db69db5e1c..c5ce0bf1b08ecf 100644
@@ -2243,8 +2243,8 @@ static void w83795_remove(struct i2c_client *client)
 
 
 static const struct i2c_device_id w83795_id[] = {
-	{ "w83795g", w83795g },
-	{ "w83795adg", w83795adg },
+	{ .name = "w83795g", .driver_data = w83795g },
+	{ .name = "w83795adg", .driver_data = w83795adg },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, w83795_id);
drivers/hwmon/w83l785ts.c +1 -1
index df77b53a1b2f9c..e42506a3bcbeca 100644
@@ -74,7 +74,7 @@ static struct w83l785ts_data *w83l785ts_update_device(struct device *dev);
  */
 
 static const struct i2c_device_id w83l785ts_id[] = {
-	{ "w83l785ts" },
+	{ .name = "w83l785ts" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, w83l785ts_id);
drivers/hwmon/w83l786ng.c +1 -1
index 1d9109ca1585e7..a72397083cc4fe 100644
@@ -751,7 +751,7 @@ w83l786ng_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id w83l786ng_id[] = {
-	{ "w83l786ng" },
+	{ .name = "w83l786ng" },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, w83l786ng_id);
Signature · 1 line
2.53.0
author maintainer
#215 lore raw

PATCH 215/744 hwmon: (pmbus/max34440): add support adpm12250

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Alexis Czezar Torreno <[email protected]>

[ Upstream commit 479bfeba2eb62666cd4b981c8e721c61dcf36e7d ]

ADPM12250 is a quarter brick DC/DC Power Module. It is a high power non-isolated converter capable of delivering regulated 12V with continuous power level of 2500W. Uses PMBus.

Stable-dep-of: af01dab0c39a ("hwmon: (pmbus/max34440) block unsupported VIN and IIN limit registers")

---
 Documentation/hwmon/max34440.rst | 27 ++++++++++++-------
 drivers/hwmon/pmbus/max34440.c   | 45 +++++++++++++++++++++++++++++---
 2 files changed, 60 insertions(+), 12 deletions(-)
Documentation/hwmon/max34440.rst +18 -9
index d6d4fbc863d96c..e7421f4dbf38fc 100644
@@ -19,6 +19,14 @@ Supported chips:
 
     Datasheet: -
 
+  * ADI ADPM12250
+
+    Prefixes: 'adpm12250'
+
+    Addresses scanned: -
+
+    Datasheet: -
+
   * Maxim MAX34440
 
     Prefixes: 'max34440'
@@ -87,11 +95,11 @@ This driver supports multiple devices: hardware monitoring for Maxim MAX34440
 PMBus 6-Channel Power-Supply Manager, MAX34441 PMBus 5-Channel Power-Supply
 Manager and Intelligent Fan Controller, and MAX34446 PMBus Power-Supply Data
 Logger; PMBus Voltage Monitor and Sequencers for MAX34451, MAX34460, and
-MAX34461; PMBus DC/DC Power Module ADPM12160, and ADPM12200. The MAX34451
-supports monitoring voltage or current of 12 channels based on GIN pins. The
-MAX34460 supports 12 voltage channels, and the MAX34461 supports 16 voltage
-channels. The ADPM12160, and ADPM12200 also monitors both input and output
-of voltage and current.
+MAX34461; PMBus DC/DC Power Module ADPM12160, ADPM12200, and ADPM12250. The
+MAX34451 supports monitoring voltage or current of 12 channels based on GIN
+pins. The MAX34460 supports 12 voltage channels, and the MAX34461 supports 16
+voltage channels. The ADPM12160, ADPM12200, and ADPM12250 also monitors both
+input and output of voltage and current.
 
 The driver is a client driver to the core PMBus driver. Please see
 Documentation/hwmon/pmbus.rst for details on PMBus client drivers.
@@ -149,7 +157,7 @@ in[1-6]_reset_history	Write any value to reset history.
 .. note::
 
     - MAX34446 only supports in[1-4].
-    - ADPM12160, and ADPM12200 only supports in[1-2]. Label is "vin1"
+    - ADPM12160, ADPM12200, and ADPM12250 only supports in[1-2]. Label is "vin1"
       and "vout1" respectively.
 
 Curr
@@ -172,8 +180,9 @@ curr[1-6]_reset_history	Write any value to reset history.
 
     - in6 and curr6 attributes only exist for MAX34440.
     - MAX34446 only supports curr[1-4].
-    - For ADPM12160, and ADPM12200, curr[1] is "iin1" and curr[2-6]
-      are "iout[1-5]".
+    - For ADPM12160, ADPM12200, and ADPM12250, curr[1] is "iin1"
+    - For ADPM12160, and ADPM12200 curr[2-6] are "iout[1-5]".
+    - For ADPM12250, curr[2-4] are "iout[1-3]".
 
 Power
 ~~~~~
@@ -209,7 +218,7 @@ temp[1-8]_reset_history	Write any value to reset history.
 .. note::
    - temp7 and temp8 attributes only exist for MAX34440.
    - MAX34446 only supports temp[1-3].
-   - ADPM12160, and ADPM12200 only supports temp[1].
+   - ADPM12160, ADPM12200, and ADPM12250 only supports temp[1].
 
 
 .. note::
drivers/hwmon/pmbus/max34440.c +42 -3

81 lines not on this page · raw message

Signature · 1 line
2.53.0
author maintainer
#216 lore raw

PATCH 216/744 hwmon: (pmbus/max34440) block unsupported VIN and IIN limit registers

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Alexis Czezar Torreno <[email protected]>

[ Upstream commit af01dab0c39a7aefc47a109201e4134ea6bd3005 ]

MAX34451 and ADPM chips do not support standard PMBus VIN/IIN limit registers, manufacturer specific min/max registers, or undercurrent or undertemperature fault limits. STATUS_BYTE and STATUS_OTHER are also not available. Accessing these non-existent registers during driver initialization triggers a CML error and asserts ALERT. Handled by blocking these functions during read/write.

Fixes 7a001dbab4ad ("hwmon: (pmbus/max34440) Add support for MAX34451.")
Fixes 629cf8f6c23a ("hwmon: (pmbus/max34440) Add support for ADPM12160")
Fixes 2e0b52f1ae88 ("hwmon: (pmbus/max34440): add support adpm12200")
Fixes 479bfeba2eb6 ("hwmon: (pmbus/max34440): add support adpm12250")
---
 drivers/hwmon/pmbus/max34440.c | 80 ++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)
drivers/hwmon/pmbus/max34440.c +80 -0
index 74876d2207fbe4..e56057e9273c16 100644
@@ -88,6 +88,33 @@ static int max34440_read_word_data(struct i2c_client *client, int page,
 		ret = pmbus_read_word_data(client, page, phase,
 					   data->iout_oc_warn_limit);
 		break;
+	case PMBUS_VIN_OV_FAULT_LIMIT:
+	case PMBUS_VIN_OV_WARN_LIMIT:
+	case PMBUS_VIN_UV_WARN_LIMIT:
+	case PMBUS_VIN_UV_FAULT_LIMIT:
+	case PMBUS_MFR_VIN_MIN:
+	case PMBUS_MFR_VIN_MAX:
+	case PMBUS_IIN_OC_WARN_LIMIT:
+	case PMBUS_IIN_OC_FAULT_LIMIT:
+	case PMBUS_MFR_IIN_MAX:
+	case PMBUS_MFR_VOUT_MIN:
+	case PMBUS_MFR_VOUT_MAX:
+	case PMBUS_IOUT_UC_FAULT_LIMIT:
+	case PMBUS_MFR_IOUT_MAX:
+	case PMBUS_UT_WARN_LIMIT:
+	case PMBUS_UT_FAULT_LIMIT:
+	case PMBUS_MFR_MAX_TEMP_1:
+		/*
+		 * MAX34451/ADPM family do not support VIN/IIN limit registers,
+		 * manufacturer-specific min/max registers, or undercurrent/
+		 * undertemperature fault limits. Accessing these triggers CML
+		 * error and asserts ALERT.
+		 */
+		if (data->id == max34451 || data->id == adpm12160 ||
+		    data->id == adpm12200 || data->id == adpm12250)
+			return -ENXIO;
+		ret = -ENODATA;
+		break;
 	case PMBUS_VIRT_READ_VOUT_MIN:
 		ret = pmbus_read_word_data(client, page, phase,
 					   MAX34440_MFR_VOUT_MIN);
@@ -244,6 +271,51 @@ static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
 	return ret;
 }
 
+static int max34451_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	const struct max34440_data *data = to_max34440_data(info);
+
+	switch (reg) {
+	case PMBUS_STATUS_BYTE:
+	case PMBUS_STATUS_OTHER:
+		/*
+		 * MAX34451/ADPM family do not support STATUS_BYTE or
+		 * STATUS_OTHER registers. Accessing them triggers CML
+		 * error and asserts ALERT.
+		 */
+		if (data->id == max34451 || data->id == adpm12160 ||
+		    data->id == adpm12200 || data->id == adpm12250)
+			return -ENXIO;
+		return -ENODATA;
+	default:
+		return -ENODATA;
+	}
+}
+
+static int max34451_write_byte_data(struct i2c_client *client, int page,
+				    int reg, u8 byte)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	const struct max34440_data *data = to_max34440_data(info);
+
+	switch (reg) {
+	case PMBUS_STATUS_BYTE:
+	case PMBUS_STATUS_OTHER:
+		/*
+		 * MAX34451/ADPM family do not support STATUS_BYTE or
+		 * STATUS_OTHER registers. Writing to them triggers CML
+		 * error and asserts ALERT.
+		 */
+		if (data->id == max34451 || data->id == adpm12160 ||
+		    data->id == adpm12200 || data->id == adpm12250)
+			return -ENXIO;
+		return -ENODATA;
+	default:
+		return -ENODATA;
+	}
+}
+
 static int max34451_set_supported_funcs(struct i2c_client *client,
 					 struct max34440_data *data)
 {
@@ -363,7 +435,9 @@ static struct pmbus_driver_info max34440_info[] = {
 		.func[9] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT,
 		.func[10] = PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT,
 		.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.read_byte_data = max34451_read_byte_data,
 		.read_word_data = max34440_read_word_data,
+		.write_byte_data = max34451_write_byte_data,
 		.write_word_data = max34440_write_word_data,
 	},
 	[adpm12200] = {
@@ -399,7 +473,9 @@ static struct pmbus_driver_info max34440_info[] = {
 		.func[10] = PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT,
 		.func[14] = PMBUS_HAVE_IOUT,
 		.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.read_byte_data = max34451_read_byte_data,
 		.read_word_data = max34440_read_word_data,
+		.write_byte_data = max34451_write_byte_data,
 		.write_word_data = max34440_write_word_data,
 	},
 	[adpm12250] = {
@@ -433,7 +509,9 @@ static struct pmbus_driver_info max34440_info[] = {
 		.func[10] = PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT,
 		.func[14] = PMBUS_HAVE_IOUT,
 		.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.read_byte_data = max34451_read_byte_data,
 		.read_word_data = max34440_read_word_data,
+		.write_byte_data = max34451_write_byte_data,
 		.write_word_data = max34440_write_word_data,
 	},
 	[max34440] = {
@@ -581,7 +659,9 @@ static struct pmbus_driver_info max34440_info[] = {
 		.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
 		.func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
 		.func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.read_byte_data = max34451_read_byte_data,
 		.read_word_data = max34440_read_word_data,
+		.write_byte_data = max34451_write_byte_data,
 		.write_word_data = max34440_write_word_data,
 		.page_change_delay = MAX34440_PAGE_CHANGE_DELAY,
 	},
Signature · 1 line
2.53.0
author maintainer
#217 lore raw

PATCH 217/744 hwmon: (asus-ec-sensors) fix looping over banks while reading from EC

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eugene Shalygin <[email protected]>

[ Upstream commit e741d13cc2abfc6fccebe2008057aa52e285223e ]

Do not assume there are only bank 0 and bank 1 available, just use '!=' for bank comparison.

Fixes d0ddfd241e57 ("hwmon: (asus-ec-sensors) add driver for ASUS EC")
---
 drivers/hwmon/asus-ec-sensors.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwmon/asus-ec-sensors.c +1 -1
index b5d97a27f80d32..d0a58207b00d3b 100644
@@ -1154,7 +1154,7 @@ static int asus_ec_block_read(const struct device *dev,
 		}
 		for (ireg = 0; ireg < ec->nr_registers; ireg++) {
 			reg_bank = register_bank(ec->registers[ireg]);
-			if (reg_bank < bank) {
+			if (reg_bank != bank) {
 				continue;
 			}
 			ec_read(register_index(ec->registers[ireg]),
Signature · 1 line
2.53.0
author maintainer
#218 lore raw

PATCH 218/744 hwmon: (asus-ec-sensors) fix EC read intervals

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eugene Shalygin <[email protected]>

[ Upstream commit 60710b2af13b81da71b429d3f8b19dd70310729d ]

Take INITIAL_JIFFIES into account when setting up next update time.

Fixes d0ddfd241e57 ("hwmon: (asus-ec-sensors) add driver for ASUS EC")
---
 drivers/hwmon/asus-ec-sensors.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/hwmon/asus-ec-sensors.c +4 -4
index d0a58207b00d3b..181fbb9511794c 100644
@@ -974,7 +974,7 @@ struct ec_sensors_data {
 	/* sorted list of unique register banks */
 	u8 banks[ASUS_EC_MAX_BANK + 1];
 	/* in jiffies */
-	unsigned long last_updated;
+	u64 next_update;
 	struct lock_data lock_data;
 	/* number of board EC sensors */
 	u8 nr_sensors;
@@ -1243,13 +1243,12 @@ static int get_cached_value_or_update(const struct device *dev,
 				      int sensor_index,
 				      struct ec_sensors_data *state, s32 *value)
 {
-	if (time_after(jiffies, state->last_updated + HZ)) {
+	if (time_after64(get_jiffies_64(), state->next_update)) {
 		if (update_ec_sensors(dev, state)) {
 			dev_err(dev, "update_ec_sensors() failure\n");
 			return -EIO;
 		}
-
-		state->last_updated = jiffies;
+		state->next_update = get_jiffies_64() + HZ;
 	}
 
 	*value = state->sensors[sensor_index].cached_value;
@@ -1367,6 +1366,7 @@ static int asus_ec_probe(struct platform_device *pdev)
 	if (!ec_data)
 		return -ENOMEM;
 
+	ec_data->next_update = INITIAL_JIFFIES;
 	dev_set_drvdata(dev, ec_data);
 	ec_data->board_info = pboard_info;
 
Signature · 1 line
2.53.0
author maintainer
#219 lore raw

PATCH 219/744 hwmon: (asus-ec-sensors) add missed handle for ENOMEM

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eugene Shalygin <[email protected]>

[ Upstream commit 9813c1f49efeadbcb17e4a41972350ac783f9cac ]

Add missing return value check in the setup function.

Fixes d0ddfd241e57 ("hwmon: (asus-ec-sensors) add driver for ASUS EC")
---
 drivers/hwmon/asus-ec-sensors.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/hwmon/asus-ec-sensors.c +5 -3
index 181fbb9511794c..7c281c6005ec62 100644
@@ -1460,9 +1460,11 @@ static int asus_ec_probe(struct platform_device *pdev)
 		if (!nr_count[type])
 			continue;
 
-		asus_ec_hwmon_add_chan_info(asus_ec_hwmon_chan, dev,
-					     nr_count[type], type,
-					     hwmon_attributes[type]);
+		status = asus_ec_hwmon_add_chan_info(asus_ec_hwmon_chan, dev,
+						     nr_count[type], type,
+						     hwmon_attributes[type]);
+		if (status)
+			return status;
 		*ptr_asus_ec_ci++ = asus_ec_hwmon_chan++;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#220 lore raw

PATCH 220/744 smb: client: validate DFS referral PathConsumed

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Yichong Chen <[email protected]>

[ Upstream commit f6f5ee2aa33b350c671721b965251c42cebb962e ]

parse_dfs_referrals() validates that the response contains the fixed referral entry array and, on for-next, the per-referral string offsets. However, the response also contains a PathConsumed value that is later used for DFS path parsing.

If a malformed response provides a PathConsumed value larger than the search name, later DFS parsing can advance beyond the end of the path.

Validate PathConsumed against the search name length before storing it in the parsed referral.

Fixes 4ecce920e13a ("CIFS: move DFS response parsing out of SMB1 code")
---
 fs/smb/client/misc.c | 34 +++++++++++++++++++++++++---------
 1 file changed, 25 insertions(+), 9 deletions(-)
fs/smb/client/misc.c +25 -9
index ee1728eec8aa0a..f8bc1b8d3fdeae 100644
@@ -678,6 +678,8 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
 	int i, rc = 0;
 	char *data_end;
 	struct dfs_referral_level_3 *ref;
+	unsigned int path_consumed;
+	size_t search_name_len;
 
 	if (rsp_size < sizeof(*rsp)) {
 		cifs_dbg(VFS | ONCE,
@@ -724,6 +726,7 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
 		rc = -ENOMEM;
 		goto parse_DFS_referrals_exit;
 	}
+	search_name_len = strlen(searchName);
 
 	/* collect necessary data from referrals */
 	for (i = 0; i < *num_of_nodes; i++) {
@@ -732,21 +735,34 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
 		struct dfs_info3_param *node = (*target_nodes)+i;
 
 		node->flags = le32_to_cpu(rsp->DFSFlags);
+		path_consumed = le16_to_cpu(rsp->PathConsumed);
 		if (is_unicode) {
-			__le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
-						GFP_KERNEL);
-			if (tmp == NULL) {
+			size_t search_name_utf16_len = search_name_len * 2 + 2;
+			__le16 *tmp;
+
+			if (path_consumed > search_name_utf16_len) {
+				rc = -EINVAL;
+				goto parse_DFS_referrals_exit;
+			}
+
+			tmp = kmalloc(search_name_utf16_len, GFP_KERNEL);
+			if (!tmp) {
 				rc = -ENOMEM;
 				goto parse_DFS_referrals_exit;
 			}
-			cifsConvertToUTF16((__le16 *) tmp, searchName,
+			cifsConvertToUTF16((__le16 *)tmp, searchName,
 					   PATH_MAX, nls_codepage, remap);
-			node->path_consumed = cifs_utf16_bytes(tmp,
-					le16_to_cpu(rsp->PathConsumed),
-					nls_codepage);
+			node->path_consumed = cifs_utf16_bytes(tmp, path_consumed,
+							       nls_codepage);
 			kfree(tmp);
-		} else
-			node->path_consumed = le16_to_cpu(rsp->PathConsumed);
+		} else {
+			if (path_consumed > search_name_len) {
+				rc = -EINVAL;
+				goto parse_DFS_referrals_exit;
+			}
+
+			node->path_consumed = path_consumed;
+		}
 
 		node->server_type = le16_to_cpu(ref->ServerType);
 		node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
Signature · 1 line
2.53.0
author maintainer
#221 lore raw

PATCH 221/744 drm/i915/backlight: Remove DP_EDP_BACKLIGHT_AUX_ENABLE_CAP check for DPCD backlight

In reply to Greg Kroah-Hartman

7.1-stable review patch. If anyone has any objections, please let me know.

------------------

From: Suraj Kandpal <[email protected]>

[ Upstream commit a411ea4a87162898d2a0547fdfb721ddb7626be3 ]

Turns out some panels allow only AUX based backlight
by just setting the DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP and not setting the DP_EDP_BACKLIGHT_AUX_ENABLE_CAP.
If we make DP_EDP_BACKLIGHT_AUX_ENABLE_CAP a necessity for AUX based DPCD backlight these panels loose the ability to manipulate backlight via AUX, especially ones with no PWM controller. Remove this check from function so that panels who do not advertise DP_EDP_BACKLIGHT_AUX_ENABLE_CAP but advertise DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP are able to manipulate backlight again.

Fixes ed8be780bdbc ("drm/i915/backlight: Fix VESA backlight possible check condition")
(cherry picked from commit 7d594b24c915afb4b0c5fb8875403253daef5b24)
---
 drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)
drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +1 -6
index 7a6c07f6aaeb4b..266e042e00237c 100644
@@ -615,12 +615,7 @@ check_if_vesa_backlight_possible(struct intel_dp *intel_dp)
 	int ret;
 	u8 bit_min, bit_max;
 
-	/*
-	 * Since we only support Fully AUX Based VESA Backlight interface make sure
-	 * backlight enable is possible via AUX along with backlight adjustment
-	 */
-	if (!(intel_dp->edp_dpcd[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP &&
-	      intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP))
+	if (!(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP))
 		return false;
 
 	ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN, &bit_min);
Signature · 1 line
2.53.0