Skip to contentSkip to conversation

6.12.110-rc1 review

PATCH Applied Greg Kroah-Hartman 23 participants 1,469 messages Sep 12 – Sep 22 Page 4 of 11

Subsystems (7)
Stable branch Documentation VFS SCSI +3 more subsystems
lore
Share & tools
lore
author maintainer
#409 lore raw

PATCH 395/1376 perf cs-etm: Queue context packets for frontend

In reply to Greg Kroah-Hartman

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

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

From: James Clark <[email protected]>

[ Upstream commit 68ca50bc0fa64841cd73b8a1538df1d7f7eb4108 ]

PE_CONTEXT elements update the context ID and exception level, but the decoder may still have prior packets cached for frontend processing. Updating the context immediately in the decoder backend can make those cached packets get consumed with the wrong thread or EL state.

Add a CS_ETM_CONTEXT packet carrying the TID and EL to the frontend, this keeps context changes ordered with the rest of the packet stream and avoids mismatches when synthesizing samples from cached packets.

Separate the memory access function into one for the frontend and one for decoding. The frontend also needs memory access to attach the instruction to samples. Because the frontend does memory access for both previous and current packets, change all the frontend memory access function signatures to take both a tidq and packet. But backend always uses the current backend EL and thread from the tidq.

Treat context packets as a boundary for branch sample generation and remove tidq->prev_packet_thread because it's not possible to branch to a different thread, so only tracking the current thread is required for sample generation.

Fixes e573e978fb12e160 ("perf cs-etm: Inject capabilitity for CoreSight traces")
Cc Ian Rogers <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Jonathan Corbet <[email protected]>
Cc Mike Leach <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Paschalis Mpeis <[email protected]>
Cc Robert Walker <[email protected]>
Cc Shuah Khan <[email protected]>
Cc Suzuki Poulouse <[email protected]>

Stable-dep-of: 50cd0d54f1f6 ("perf cs-etm: Fix thread leaks on trace queue init failure")

---
 .../perf/util/cs-etm-decoder/cs-etm-decoder.c |  21 +-
 tools/perf/util/cs-etm.c                      | 236 +++++++++++-------
 tools/perf/util/cs-etm.h                      |   8 +-
 3 files changed, 163 insertions(+), 102 deletions(-)
tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +16 -5
index 9bf09a856b44a..c1257c5ef4256 100644
@@ -399,6 +399,8 @@ cs_etm_decoder__buffer_packet(struct cs_etm_queue *etmq,
 	packet_queue->packet_buffer[et].flags = 0;
 	packet_queue->packet_buffer[et].exception_number = UINT32_MAX;
 	packet_queue->packet_buffer[et].trace_chan_id = trace_chan_id;
+	packet_queue->packet_buffer[et].el = ocsd_EL_unknown;
+	packet_queue->packet_buffer[et].tid = -1;
 
 	if (packet_queue->packet_count == CS_ETM_PACKET_MAX_BUFFER - 1)
 		return OCSD_RESP_WAIT;
@@ -446,6 +448,7 @@ cs_etm_decoder__buffer_range(struct cs_etm_queue *etmq,
 	packet->last_instr_type = elem->last_i_type;
 	packet->last_instr_subtype = elem->last_i_subtype;
 	packet->last_instr_cond = elem->last_instr_cond;
+	packet->el = elem->context.exception_level;
 
 	if (elem->last_i_type == OCSD_INSTR_BR || elem->last_i_type == OCSD_INSTR_BR_INDIRECT)
 		packet->last_instr_taken_branch = elem->last_instr_exec;
@@ -522,7 +525,9 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,
 			const ocsd_generic_trace_elem *elem,
 			const uint8_t trace_chan_id)
 {
+	struct cs_etm_packet *packet;
 	pid_t tid = -1;
+	int ret;
 
 	/*
 	 * Process the PE_CONTEXT packets if we have a valid contextID or VMID.
@@ -543,12 +548,18 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,
 		break;
 	}
 
-	if (cs_etm__etmq_set_tid_el(etmq, tid, trace_chan_id,
-				    elem->context.exception_level))
+	if (cs_etm__etmq_update_decode_context(etmq, trace_chan_id,
+				elem->context.exception_level, tid))
 		return OCSD_RESP_FATAL_SYS_ERR;
 
-	if (tid == -1)
-		return OCSD_RESP_CONT;
+	ret = cs_etm_decoder__buffer_packet(etmq, packet_queue, trace_chan_id,
+					    CS_ETM_CONTEXT);
+	if (ret != OCSD_RESP_CONT && ret != OCSD_RESP_WAIT)
+		return ret;
+
+	packet = &packet_queue->packet_buffer[packet_queue->tail];
+	packet->tid = tid;
+	packet->el = elem->context.exception_level;
 
 	/*
 	 * A timestamp is generated after a PE_CONTEXT element so make sure
@@ -556,7 +567,7 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,
 	 */
 	cs_etm_decoder__reset_timestamp(packet_queue);
 
-	return OCSD_RESP_CONT;
+	return ret;
 }
 
 static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
tools/perf/util/cs-etm.c +141 -95

533 lines not on this page · raw message

tools/perf/util/cs-etm.h +6 -2
index a8caeea720aa1..dfc9aeacfd0b6 100644
@@ -158,6 +158,7 @@ enum cs_etm_sample_type {
 	CS_ETM_DISCONTINUITY,
 	CS_ETM_EXCEPTION,
 	CS_ETM_EXCEPTION_RET,
+	CS_ETM_CONTEXT,
 };
 
 enum cs_etm_isa {
@@ -184,6 +185,8 @@ struct cs_etm_packet {
 	u8 last_instr_size;
 	u8 trace_chan_id;
 	int cpu;
+	int el;
+	pid_t tid;
 };
 
 #define CS_ETM_PACKET_MAX_BUFFER 1024
@@ -244,8 +247,9 @@ enum cs_etm_pid_fmt {
 #include <opencsd/ocsd_if_types.h>
 int cs_etm__get_cpu(struct cs_etm_queue *etmq, u8 trace_chan_id, int *cpu);
 enum cs_etm_pid_fmt cs_etm__get_pid_fmt(struct cs_etm_queue *etmq);
-int cs_etm__etmq_set_tid_el(struct cs_etm_queue *etmq, pid_t tid,
-			    u8 trace_chan_id, ocsd_ex_level el);
+int cs_etm__etmq_update_decode_context(struct cs_etm_queue *etmq,
+				       u8 trace_chan_id, ocsd_ex_level el,
+				       pid_t tid);
 bool cs_etm__etmq_is_timeless(struct cs_etm_queue *etmq);
 void cs_etm__etmq_set_traceid_queue_timestamp(struct cs_etm_queue *etmq,
 					      u8 trace_chan_id);
Signature · 1 line
2.53.0
author maintainer
#410 lore raw

PATCH 396/1376 perf cs-etm: Fix thread leaks on trace queue init failure

In reply to Greg Kroah-Hartman

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

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

From: Leo Yan <[email protected]>

[ Upstream commit 50cd0d54f1f6dd9b3de7c0ad101bd41d06206ace ]

cs_etm__init_traceid_queue() allocates the frontend and decode threads, if a later allocation fails, the error path does not drop thread reference that was already acquired.

Release both thread pointers with thread__zput() on the error path, so does not leak thread references or leave stale pointers behind.

Fixes 951ccccdc715 ("perf cs-etm: Only track threads instead of PID and TIDs")
---
 tools/perf/util/cs-etm.c | 4 ++++
 1 file changed, 4 insertions(+)
tools/perf/util/cs-etm.c +4 -0
index 9e3a4a676535a..29f0211324970 100644
@@ -620,6 +620,8 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
 					       queue->tid);
 	tidq->decode_thread = machine__findnew_thread(&etm->session->machines.host, -1,
 					       queue->tid);
+	if (!tidq->frontend_thread || !tidq->decode_thread)
+		goto out;
 
 	tidq->packet = zalloc(sizeof(struct cs_etm_packet));
 	if (!tidq->packet)
@@ -654,6 +656,8 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
 	zfree(&tidq->prev_packet);
 	zfree(&tidq->packet);
 out:
+	thread__zput(tidq->frontend_thread);
+	thread__zput(tidq->decode_thread);
 	return rc;
 }
 
Signature · 1 line
2.53.0
author maintainer
#411 lore raw

PATCH 397/1376 perf/x86/amd/uncore: Add group validation

In reply to Greg Kroah-Hartman

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

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

From: Sandipan Das <[email protected]>

[ Upstream commit edda9051e267b7390c7ce24b1b71434414ad156e ]

The amd_uncore driver currently does not validate event groups and allows creation of groups with more events than the number of available hardware counters. Because of this, pmu->event_init() succeeds but counter assignment fails later in pmu->add() which returns -EBUSY once all counters are exhausted.

Address this by introducing group validation in the pmu->event_init() path. Since the uncore PMUs have no per-event constraints and all counters of a PMU are interchangeable, validation is reduced to just counting the group members that target a PMU and ensuring that they fit within the available set of counters.

---
 arch/x86/events/amd/uncore.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)
arch/x86/events/amd/uncore.c +31 -0
index cad240e88b4ff..06c5e485fd6e0 100644
@@ -206,6 +206,29 @@ static void amd_uncore_del(struct perf_event *event, int flags)
 	hwc->idx = -1;
 }
 
+static bool amd_uncore_group_valid(struct perf_event *event)
+{
+	struct amd_uncore_pmu *pmu = event_to_amd_uncore_pmu(event);
+	struct perf_event *leader = event->group_leader;
+	struct perf_event *sibling;
+	int counters = 0;
+
+	if (leader->pmu == event->pmu)
+		counters++;
+
+	for_each_sibling_event(sibling, leader) {
+		if (sibling->pmu == event->pmu &&
+		    sibling->state > PERF_EVENT_STATE_OFF)
+			counters++;
+	}
+
+	/*
+	 * When pmu->event_init() is called, the event is yet to be linked to
+	 * its leader's sibling list, so it is counted separately
+	 */
+	return (counters + 1) <= pmu->num_counters;
+}
+
 static int amd_uncore_event_init(struct perf_event *event)
 {
 	struct amd_uncore_pmu *pmu;
@@ -223,6 +246,14 @@ static int amd_uncore_event_init(struct perf_event *event)
 	if (!ctx)
 		return -ENODEV;
 
+	/*
+	 * Ensure that all events in a group can be scheduled together so that
+	 * a failure can be reported at perf_event_open() time rather than
+	 * silently at pmu->add() time when no free counter is found
+	 */
+	if (event->group_leader != event && !amd_uncore_group_valid(event))
+		return -EINVAL;
+
 	/*
 	 * NB and Last level cache counters (MSRs) are shared across all cores
 	 * that share the same NB / Last level cache.  On family 16h and below,
Signature · 1 line
2.53.0
author maintainer
#412 lore raw

PATCH 398/1376 perf vendor events amd: Update Zen 5 core events

In reply to Greg Kroah-Hartman

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

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

From: Sandipan Das <[email protected]>

[ Upstream commit 047979af3bf6a118066c81099162d518de63abb1 ]

Update definitions for the following events.
* PMCx00A - Add missing unit masks
* PMCx00B - Add missing unit masks and fix descriptions
* PMCx00C - Add missing unit masks
* PMCx00D - Add missing unit masks
* PMCx025 - Add missing unit masks and fix descriptions

Fixes 45c072f2537a ("perf vendor events amd: Add Zen 5 core events")
---
 .../arch/x86/amdzen5/floating-point.json      | 130 +++++++++++++++---
 .../arch/x86/amdzen5/load-store.json          |   8 +-
 2 files changed, 120 insertions(+), 18 deletions(-)
tools/perf/pmu-events/arch/x86/amdzen5/floating-point.json +113 -17
index 9204bfb1d69e0..569975b53cc33 100644
@@ -179,6 +179,30 @@
     "BriefDescription": "Retired scalar floating-point blend ops.",
     "UMask": "0x09"
   },
+  {
+    "EventName": "fp_ops_retired_by_type.scalar_mov",
+    "EventCode": "0x0a",
+    "BriefDescription": "Retired scalar floating-point MOV ops.",
+    "UMask": "0x0a"
+  },
+  {
+    "EventName": "fp_ops_retired_by_type.scalar_shuffle",
+    "EventCode": "0x0a",
+    "BriefDescription": "Retired scalar floating-point shuffle ops (may include instructions not necessarily thought of as including shuffles e.g. horizontal add, dot product, and certain MOV instructions).",
+    "UMask": "0x0b"
+  },
+  {
+    "EventName": "fp_ops_retired_by_type.scalar_bfloat",
+    "EventCode": "0x0a",
+    "BriefDescription": "Retired scalar floating-point bfloat ops.",
+    "UMask": "0x0c"
+  },
+  {
+    "EventName": "fp_ops_retired_by_type.scalar_logical",
+    "EventCode": "0x0a",
+    "BriefDescription": "Retired scalar floating-point logical ops.",
+    "UMask": "0x0d"
+  },
   {
     "EventName": "fp_ops_retired_by_type.scalar_other",
     "EventCode": "0x0a",
@@ -245,12 +269,24 @@
     "BriefDescription": "Retired vector floating-point blend ops.",
     "UMask": "0x90"
   },
+  {
+    "EventName": "fp_ops_retired_by_type.vector_mov",
+    "EventCode": "0x0a",
+    "BriefDescription": "Retired vector floating-point MOV ops.",
+    "UMask": "0xa0"
+  },
   {
     "EventName": "fp_ops_retired_by_type.vector_shuffle",
     "EventCode": "0x0a",
     "BriefDescription": "Retired vector floating-point shuffle ops (may include instructions not necessarily thought of as including shuffles e.g. horizontal add, dot product, and certain MOV instructions).",
     "UMask": "0xb0"
   },
+  {
+    "EventName": "fp_ops_retired_by_type.vector_bfloat",
+    "EventCode": "0x0a",
+    "BriefDescription": "Retired vector floating-point bfloat ops.",
+    "UMask": "0xc0"
+  },
   {
     "EventName": "fp_ops_retired_by_type.vector_logical",
     "EventCode": "0x0a",
@@ -278,7 +314,7 @@
   {
     "EventName": "sse_avx_ops_retired.mmx_add",
     "EventCode": "0x0b",
-    "BriefDescription": "Retired MMX integer add.",
+    "BriefDescription": "Retired MMX integer add ops.",
     "UMask": "0x01"
   },
   {
@@ -299,16 +335,34 @@
     "BriefDescription": "Retired MMX integer multiply-accumulate ops.",
     "UMask": "0x04"
   },
+  {
+    "EventName": "sse_avx_ops_retired.mmx_aes",
+    "EventCode": "0x0b",
+    "BriefDescription": "Retired MMX integer AES ops.",
+    "UMask": "0x05"
+  },
+  {
+    "EventName": "sse_avx_ops_retired.mmx_sha",
+    "EventCode": "0x0b",
+    "BriefDescription": "Retired MMX integer SHA ops.",
+    "UMask": "0x06"
+  },
   {
     "EventName": "sse_avx_ops_retired.mmx_cmp",
     "EventCode": "0x0b",
     "BriefDescription": "Retired MMX integer compare ops.",
     "UMask": "0x07"
   },
+  {
+    "EventName": "sse_avx_ops_retired.mmx_cvt",
+    "EventCode": "0x0b",
+    "BriefDescription": "Retired MMX integer convert or pack ops.",
+    "UMask": "0x08"
+  },
   {
     "EventName": "sse_avx_ops_retired.mmx_shift",
     "EventCode": "0x0b",
-    "BriefDescription": "Retired MMX integer shift ops.",
+    "BriefDescription": "Retired MMX integer shift or rotate ops.",
     "UMask": "0x09"
   },
   {
@@ -324,9 +378,9 @@
     "UMask": "0x0b"
   },
   {
-    "EventName": "sse_avx_ops_retired.mmx_pack",
+    "EventName": "sse_avx_ops_retired.mmx_vnni",
     "EventCode": "0x0b",
-    "BriefDescription": "Retired MMX integer pack ops.",
+    "BriefDescription": "Retired MMX integer VNNI ops.",
     "UMask": "0x0c"
   },
   {
@@ -390,15 +444,15 @@
     "UMask": "0x70"
   },
   {
-    "EventName": "sse_avx_ops_retired.sse_avx_clm",
+    "EventName": "sse_avx_ops_retired.sse_avx_cvt",
     "EventCode": "0x0b",
-    "BriefDescription": "Retired SSE and AVX integer CLM ops.",
+    "BriefDescription": "Retired SSE and AVX integer convert or pack ops.",
     "UMask": "0x80"
   },
   {
     "EventName": "sse_avx_ops_retired.sse_avx_shift",
     "EventCode": "0x0b",
-    "BriefDescription": "Retired SSE and AVX integer shift ops.",
+    "BriefDescription": "Retired SSE and AVX integer shift or rotate ops.",
     "UMask": "0x90"
   },
   {
@@ -414,9 +468,9 @@
     "UMask": "0xb0"
   },
   {
-    "EventName": "sse_avx_ops_retired.sse_avx_pack",
+    "EventName": "sse_avx_ops_retired.sse_avx_vnni",
     "EventCode": "0x0b",
-    "BriefDescription": "Retired SSE and AVX integer pack ops.",
+    "BriefDescription": "Retired SSE and AVX integer VNNI ops.",
     "UMask": "0xc0"
   },
   {
@@ -497,12 +551,24 @@
     "BriefDescription": "Retired 128-bit packed floating-point blend ops.",
     "UMask": "0x09"
   },
+  {
+    "EventName": "fp_pack_ops_retired.fp128_mov",
+    "EventCode": "0x0c",
+    "BriefDescription": "Retired 128-bit packed floating-point MOV ops.",
+    "UMask": "0x0a"
+  },
   {
     "EventName": "fp_pack_ops_retired.fp128_shuffle",
     "EventCode": "0x0c",
     "BriefDescription": "Retired 128-bit packed floating-point shuffle ops (may include instructions not necessarily thought of as including shuffles e.g. horizontal add, dot product, and certain MOV instructions).",
     "UMask": "0x0b"
   },
+  {
+    "EventName": "fp_pack_ops_retired.fp128_bfloat",
+    "EventCode": "0x0c",
+    "BriefDescription": "Retired 128-bit packed floating-point bfloat ops.",
+    "UMask": "0x0c"
+  },
   {
     "EventName": "fp_pack_ops_retired.fp128_logical",
     "EventCode": "0x0c",
@@ -575,12 +641,24 @@
     "BriefDescription": "Retired 256-bit packed floating-point blend ops.",
     "UMask": "0x90"
   },
+  {
+    "EventName": "fp_pack_ops_retired.fp256_mov",
+    "EventCode": "0x0c",
+    "BriefDescription": "Retired 256-bit packed floating-point MOV ops.",
+    "UMask": "0xa0"
+  },
   {
     "EventName": "fp_pack_ops_retired.fp256_shuffle",
     "EventCode": "0x0c",
     "BriefDescription": "Retired 256-bit packed floating-point shuffle ops (may include instructions not necessarily thought of as including shuffles e.g. horizontal add, dot product, and certain MOV instructions).",
     "UMask": "0xb0"
   },
+  {
+    "EventName": "fp_pack_ops_retired.fp256_bfloat",
+    "EventCode": "0x0c",
+    "BriefDescription": "Retired 256-bit packed floating-point bfloat ops.",
+    "UMask": "0xc0"
+  },
   {
     "EventName": "fp_pack_ops_retired.fp256_logical",
     "EventCode": "0x0c",
@@ -648,15 +726,15 @@
     "UMask": "0x07"
   },
   {
-    "EventName": "packed_int_op_type.int128_clm",
+    "EventName": "packed_int_op_type.int128_cvt",
     "EventCode": "0x0d",
-    "BriefDescription": "Retired 128-bit packed integer CLM ops.",
+    "BriefDescription": "Retired 128-bit packed integer convert or pack ops.",
     "UMask": "0x08"
   },
   {
     "EventName": "packed_int_op_type.int128_shift",
     "EventCode": "0x0d",
-    "BriefDescription": "Retired 128-bit packed integer shift ops.",
+    "BriefDescription": "Retired 128-bit packed integer shift or rotate ops.",
     "UMask": "0x09"
   },
   {
@@ -672,9 +750,9 @@
     "UMask": "0x0b"
   },
   {
-    "EventName": "packed_int_op_type.int128_pack",
+    "EventName": "packed_int_op_type.int128_vnni",
     "EventCode": "0x0d",
-    "BriefDescription": "Retired 128-bit packed integer pack ops.",
+    "BriefDescription": "Retired 128-bit packed integer VNNI ops.",
     "UMask": "0x0c"
   },
   {
@@ -719,16 +797,34 @@
     "BriefDescription": "Retired 256-bit packed integer multiply-accumulate ops.",
     "UMask": "0x40"
   },
+  {
+    "EventName": "packed_int_op_type.int256_aes",
+    "EventCode": "0x0d",
+    "BriefDescription": "Retired 256-bit packed integer AES ops.",
+    "UMask": "0x50"
+  },
+  {
+    "EventName": "packed_int_op_type.int256_sha",
+    "EventCode": "0x0d",
+    "BriefDescription": "Retired 256-bit packed integer SHA ops.",
+    "UMask": "0x60"
+  },
   {
     "EventName": "packed_int_op_type.int256_cmp",
     "EventCode": "0x0d",
     "BriefDescription": "Retired 256-bit packed integer compare ops.",
     "UMask": "0x70"
   },
+  {
+    "EventName": "packed_int_op_type.int256_cvt",
+    "EventCode": "0x0d",
+    "BriefDescription": "Retired 256-bit packed integer convert or pack ops.",
+    "UMask": "0x80"
+  },
   {
     "EventName": "packed_int_op_type.int256_shift",
     "EventCode": "0x0d",
-    "BriefDescription": "Retired 256-bit packed integer shift ops.",
+    "BriefDescription": "Retired 256-bit packed integer shift or rotate ops.",
     "UMask": "0x90"
   },
   {
@@ -744,9 +840,9 @@
     "UMask": "0xb0"
   },
   {
-    "EventName": "packed_int_op_type.int256_pack",
+    "EventName": "packed_int_op_type.int256_vnni",
     "EventCode": "0x0d",
-    "BriefDescription": "Retired 256-bit packed integer pack ops.",
+    "BriefDescription": "Retired 256-bit packed integer VNNI ops.",
     "UMask": "0xc0"
   },
   {
tools/perf/pmu-events/arch/x86/amdzen5/load-store.json +7 -1
index 917f9d68f85a6..d1ac7ff52a4d7 100644
@@ -8,9 +8,15 @@
   {
     "EventName": "ls_locks.bus_lock",
     "EventCode": "0x25",
-    "BriefDescription": "Retired Lock instructions which caused a bus lock.",
+    "BriefDescription": "Retired lock instructions which caused a bus lock.",
     "UMask": "0x01"
   },
+  {
+    "EventName": "ls_locks.all",
+    "EventCode": "0x25",
+    "BriefDescription": "Retired lock instructions of all types.",
+    "UMask": "0x1f"
+  },
   {
     "EventName": "ls_ret_cl_flush",
     "EventCode": "0x26",
Signature · 1 line
2.53.0
author maintainer
#413 lore raw

PATCH 399/1376 hwrng: core - fix rng list on registration error

In reply to Greg Kroah-Hartman

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

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

From: Manos Pitsidianakis <[email protected]>

[ Upstream commit 3a5834db2b1ce25649f330e78efe1ccde78967fd ]

hwrng_register(rng) does the following:

1. Checks if rng has name and read methods set
2. Checks if the name already exists
3. Adds rng to global rng_list
4. May try to set rng to current_rng

If step 4 fails, it returns an error. However, it does not remove the rng from rng_list, causing a dangling reference which can result in use-after-free if the caller frees rng, since registration failed.

Add a list_del_init() cleanup step.

Fixes 2bbb6983887f ("hwrng: use rng source with best quality")
---
 drivers/char/hw_random/core.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/char/hw_random/core.c +3 -1
index c6e913497e1df..008f81a82131d 100644
@@ -597,11 +597,13 @@ int hwrng_register(struct hwrng *rng)
 			 */
 			err = set_current_rng(rng);
 			if (err)
-				goto out_unlock;
+				goto out_list_del;
 		}
 	}
 	mutex_unlock(&rng_mutex);
 	return 0;
+out_list_del:
+	list_del_init(&rng->list);
 out_unlock:
 	mutex_unlock(&rng_mutex);
 out:
Signature · 1 line
2.53.0
author maintainer
#414 lore raw

PATCH 400/1376 crypto: qat - cancel work on re-enable SR-IOV timeout

In reply to Greg Kroah-Hartman

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

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

From: Giovanni Cabiddu <[email protected]>

[ Upstream commit 455b0f3ac9e254edab9f5a873d337abe5e6e3604 ]

The QAT reset worker queues SR-IOV reenable work using a work_struct and completion embedded in an on-stack adf_sriov_dev_data. If the completion wait times out, the reset worker can return while device_sriov_wq still holds or executes the stack-backed work item.

Cancel the work on the device_sriov_wq on timeout before the stack frame unwinds.

Fixes 4469f9b23468 ("crypto: qat - re-enable sriov after pf reset")
---
 drivers/crypto/intel/qat/qat_common/adf_aer.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/crypto/intel/qat/qat_common/adf_aer.c +2 -0
index bd81458bcf327..403e53347f8e2 100644
@@ -140,6 +140,8 @@ static void adf_device_reset_worker(struct work_struct *work)
 	queue_work(device_sriov_wq, &sriov_data.sriov_work);
 	if (wait_for_completion_timeout(&sriov_data.compl, wait_jiffies))
 		adf_pf2vf_notify_restarted(accel_dev);
+	else
+		cancel_work_sync(&sriov_data.sriov_work);
 
 	adf_dev_restarted_notify(accel_dev);
 	clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
Signature · 1 line
2.53.0
author maintainer
#415 lore raw

PATCH 401/1376 crypto: qat - clear AES key schedule from stack

In reply to Greg Kroah-Hartman

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

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

From: Giovanni Cabiddu <[email protected]>

[ Upstream commit d41a9fcfb7f9ee36e4a4aaf5e7996bca6be1e7a9 ]

qat_alg_xts_reverse_key() expands the forward XTS AES key on the stack. That schedule contains key material and can remain in the stack frame.

Clear the temporary crypto_aes_ctx with memzero_explicit() after the copy.

Fixes 5106dfeaeabe ("crypto: qat - add AES-XTS support for QAT GEN4 devices")
---
 drivers/crypto/intel/qat/qat_common/qat_algs.c | 1 +
 1 file changed, 1 insertion(+)
drivers/crypto/intel/qat/qat_common/qat_algs.c +1 -0
index d69cc1e5e0239..274bcc83a1fc2 100644
@@ -481,6 +481,7 @@ static void qat_alg_xts_reverse_key(const u8 *key_forward, unsigned int keylen,
 		memcpy(key_reverse + AES_BLOCK_SIZE, key - AES_BLOCK_SIZE,
 		       AES_BLOCK_SIZE);
 	}
+	memzero_explicit(&aes_expanded, sizeof(aes_expanded));
 }
 
 static void qat_alg_skcipher_init_dec(struct qat_alg_skcipher_ctx *ctx,
Signature · 1 line
2.53.0
author maintainer
#416 lore raw

PATCH 402/1376 crypto: atmel-ecc - replace min_t with min

In reply to Greg Kroah-Hartman

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

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

From: Thorsten Blum <[email protected]>

[ Upstream commit 5b085b2a038a1458f9398cb3b3b03cba6e38e1e0 ]

Use the simpler min() macro since the values are all unsigned and compatible.

Stable-dep-of: f240f9b588f4 ("crypto: atmel-ecc - reject hardware ECDH without a public key")

---
 drivers/crypto/atmel-ecc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/crypto/atmel-ecc.c +2 -2
index 9da5a03880807..0ce56b095805a 100644
@@ -56,7 +56,7 @@ static void atmel_ecdh_done(struct atmel_i2c_work_data *work_data, void *areq,
 		goto free_work_data;
 
 	/* might want less than we've got */
-	n_sz = min_t(size_t, ATMEL_ECC_NIST_P256_N_SIZE, req->dst_len);
+	n_sz = min(ATMEL_ECC_NIST_P256_N_SIZE, req->dst_len);
 
 	/* copy the shared secret */
 	copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst, n_sz),
@@ -150,7 +150,7 @@ static int atmel_ecdh_generate_public_key(struct kpp_request *req)
 		return -EINVAL;
 
 	/* might want less than we've got */
-	nbytes = min_t(size_t, ATMEL_ECC_PUBKEY_SIZE, req->dst_len);
+	nbytes = min(ATMEL_ECC_PUBKEY_SIZE, req->dst_len);
 
 	/* public key was saved at private key generation */
 	copied = sg_copy_from_buffer(req->dst,
Signature · 1 line
2.53.0
author maintainer
#417 lore raw

PATCH 403/1376 crypto: atmel-ecc - clean up and improve ECDH comments

In reply to Greg Kroah-Hartman

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

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

From: Thorsten Blum <[email protected]>

[ Upstream commit 3e84fb698abada239d3e35ed3d52a24dbfda5f6a ]

Improve the kerneldoc for struct atmel_ecdh_ctx by removing the stale "unsupported curves" wording, since the device only supports a single curve (P-256), and move the set_secret() constraint to the description.

In atmel_ecdh_set_secret(), clarify that the device generates the private key, and drop the redundant "only supports NIST P256" comment.

In atmel_ecdh_done() and atmel_ecdh_generate_public_key(), clarify the truncation comments. Also note that a P-256 public key consists of two 32-byte coordinates in atmel_ecdh_compute_shared_secret(), and remove the unnecessary fall-through comment and other redundant comments.

Stable-dep-of: f240f9b588f4 ("crypto: atmel-ecc - reject hardware ECDH without a public key")

---
 drivers/crypto/atmel-ecc.c | 38 ++++++++++++++------------------------
 1 file changed, 14 insertions(+), 24 deletions(-)
drivers/crypto/atmel-ecc.c +14 -24
index 0ce56b095805a..efb346e5550e8 100644
@@ -27,15 +27,14 @@ static struct atmel_ecc_driver_data driver_data;
 
 /**
  * struct atmel_ecdh_ctx - transformation context
- * @client     : pointer to i2c client device
- * @fallback   : used for unsupported curves or when user wants to use its own
- *               private key.
- * @public_key : generated when calling set_secret(). It's the responsibility
- *               of the user to not call set_secret() while
- *               generate_public_key() or compute_shared_secret() are in flight.
- * @curve_id   : elliptic curve id
- * @do_fallback: true when the device doesn't support the curve or when the user
- *               wants to use its own private key.
+ * @client: I2C client device
+ * @fallback: ECDH fallback used for caller-provided private keys
+ * @public_key: cached public key for the device-generated private key
+ * @curve_id: elliptic curve id
+ * @do_fallback: true when ECDH operations should use @fallback
+ *
+ * The caller must not invoke set_secret() while generate_public_key()
+ * or compute_shared_secret() are in flight.
  */
 struct atmel_ecdh_ctx {
 	struct i2c_client *client;
@@ -55,7 +54,7 @@ static void atmel_ecdh_done(struct atmel_i2c_work_data *work_data, void *areq,
 	if (status)
 		goto free_work_data;
 
-	/* might want less than we've got */
+	/* copy only as much as requested, capped at 32 bytes */
 	n_sz = min(ATMEL_ECC_NIST_P256_N_SIZE, req->dst_len);
 
 	/* copy the shared secret */
@@ -64,15 +63,15 @@ static void atmel_ecdh_done(struct atmel_i2c_work_data *work_data, void *areq,
 	if (copied != n_sz)
 		status = -EINVAL;
 
-	/* fall through */
 free_work_data:
 	kfree_sensitive(work_data);
 	kpp_request_complete(req, status);
 }
 
 /*
- * A random private key is generated and stored in the device. The device
- * returns the pair public key.
+ * If no private key is provided, generate one in the device and cache
+ * the corresponding public key. The generated private key never leaves
+ * the device.
  */
 static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
 				 unsigned int len)
@@ -83,9 +82,7 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
 	struct ecdh params;
 	int ret = -ENOMEM;
 
-	/* free the old public key, if any */
 	kfree(ctx->public_key);
-	/* make sure you don't free the old public key twice */
 	ctx->public_key = NULL;
 
 	if (crypto_ecdh_decode_key(buf, len, &params) < 0) {
@@ -94,7 +91,6 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
 	}
 
 	if (params.key_size) {
-		/* fallback to ecdh software implementation */
 		ctx->do_fallback = true;
 		return crypto_kpp_set_secret(ctx->fallback, buf, len);
 	}
@@ -103,11 +99,6 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
 	if (!cmd)
 		return -ENOMEM;
 
-	/*
-	 * The device only supports NIST P256 ECC keys. The public key size will
-	 * always be the same. Use a macro for the key size to avoid unnecessary
-	 * computations.
-	 */
 	public_key = kmalloc(ATMEL_ECC_PUBKEY_SIZE, GFP_KERNEL);
 	if (!public_key)
 		goto free_cmd;
@@ -120,7 +111,6 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
 	if (ret)
 		goto free_public_key;
 
-	/* save the public key */
 	memcpy(public_key, &cmd->data[RSP_DATA_IDX], ATMEL_ECC_PUBKEY_SIZE);
 	ctx->public_key = public_key;
 
@@ -149,7 +139,7 @@ static int atmel_ecdh_generate_public_key(struct kpp_request *req)
 	if (!ctx->public_key)
 		return -EINVAL;
 
-	/* might want less than we've got */
+	/* copy only as much as requested, capped at 64 bytes */
 	nbytes = min(ATMEL_ECC_PUBKEY_SIZE, req->dst_len);
 
 	/* public key was saved at private key generation */
@@ -175,7 +165,7 @@ static int atmel_ecdh_compute_shared_secret(struct kpp_request *req)
 		return crypto_kpp_compute_shared_secret(req);
 	}
 
-	/* must have exactly two points to be on the curve */
+	/* A P-256 public key must contain two 32-byte coordinates */
 	if (req->src_len != ATMEL_ECC_PUBKEY_SIZE)
 		return -EINVAL;
 
Signature · 1 line
2.53.0
author maintainer
#418 lore raw

PATCH 404/1376 crypto: atmel-ecc - reject hardware ECDH without a public key

In reply to Greg Kroah-Hartman

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

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

From: Thorsten Blum <[email protected]>

[ Upstream commit f240f9b588f4e2de89822adebf560a96b5d263ed ]

The hardware ECDH path in atmel_ecdh_compute_shared_secret() uses the private key stored in the device. However, the public key is cached only after atmel_ecdh_set_secret() successfully generated that private key for the current tfm.

atmel_ecdh_generate_public_key() already rejects requests when no public key is cached. Add the same check to atmel_ecdh_compute_shared_secret() to prevent the device from using a private key that was not generated for the current tfm.

Fixes 11105693fa05 ("crypto: atmel-ecc - introduce Microchip / Atmel ECC driver")
---
 drivers/crypto/atmel-ecc.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/crypto/atmel-ecc.c +3 -0
index efb346e5550e8..c64431380d303 100644
@@ -165,6 +165,9 @@ static int atmel_ecdh_compute_shared_secret(struct kpp_request *req)
 		return crypto_kpp_compute_shared_secret(req);
 	}
 
+	if (!ctx->public_key)
+		return -EINVAL;
+
 	/* A P-256 public key must contain two 32-byte coordinates */
 	if (req->src_len != ATMEL_ECC_PUBKEY_SIZE)
 		return -EINVAL;
Signature · 1 line
2.53.0
author maintainer
#419 lore raw

PATCH 405/1376 crypto: atmel-sha204a - fix heap info leak on I2C transfer failure

In reply to Greg Kroah-Hartman

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

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

From: Lothar Rubusch <[email protected]>

[ Upstream commit 72bbf11ba14bd7d5fbf31a1ec42fff608b657f74 ]

The nonblocking RNG path allocates a work_data structure to track the state of an in-flight asynchronous I2C request. This pointer is stored in rng->priv and later consumed by the read path once the transaction completes.

If the underlying I2C transfer fails, the completion callback is invoked with a non-zero status. In this case, the allocated work_data is not usable for producing RNG output and must not remain associated with the hwrng state.

Previously, the failure path only logged a warning but left the pointer state uncleared, which can result in subsequent read attempts observing stale state and interpreting it as valid completion data.

Fix this by freeing the pending work_data. The I2C transaction reports an error. This ensures that failed requests do not leave residual state behind that could be interpreted as valid RNG data on later reads. Clearing rng->priv is done at the subsequent call to nonblocking read.

Fixes da001fb651b0 ("crypto: atmel-i2c - add support for SHA204A random number generator")
Assisted-by Gemini:1.5 Pro [google]
---
 drivers/crypto/atmel-sha204a.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/crypto/atmel-sha204a.c +5 -1
index 8a3520c9a0ff5..d2031abbd8efa 100644
@@ -31,10 +31,14 @@ static void atmel_sha204a_rng_done(struct atmel_i2c_work_data *work_data,
 	struct atmel_i2c_client_priv *i2c_priv = work_data->ctx;
 	struct hwrng *rng = areq;
 
-	if (status)
+	if (status) {
 		dev_warn_ratelimited(&i2c_priv->client->dev,
 				     "i2c transaction failed (%d)\n",
 				     status);
+		kfree(work_data);
+		atomic_dec(&i2c_priv->tfm_count);
+		return;
+	}
 
 	rng->priv = (unsigned long)work_data;
 	atomic_dec(&i2c_priv->tfm_count);
Signature · 1 line
2.53.0
author maintainer
#420 lore raw

PATCH 406/1376 crypto: sa2ul - stop probe if context pool creation fails

In reply to Greg Kroah-Hartman

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

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

From: Pengpeng Hou <[email protected]>

[ Upstream commit d03f980a25853f6a380895119a572a3bb1194e8d ]

sa_ul_probe() calls sa_init_mem() to create the DMA pool used for security context buffers, but ignores its return value. If pool creation fails, probe still continues with DMA setup, algorithm registration and child population even though later request setup depends on that pool.

Stop probing when sa_init_mem() fails, and route that failure to the PM cleanup path without attempting to destroy an uncreated DMA pool.

Fixes 7694b6ca649f ("crypto: sa2ul - Add crypto driver")
---
 drivers/crypto/sa2ul.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/crypto/sa2ul.c +5 -1
index d1c2d129ad418..a8f5f475acbe6 100644
@@ -2426,7 +2426,10 @@ static int sa_ul_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	sa_init_mem(dev_data);
+	ret = sa_init_mem(dev_data);
+	if (ret)
+		goto disable_pm;
+
 	ret = sa_dma_init(dev_data);
 	if (ret)
 		goto destroy_dma_pool;
@@ -2461,6 +2464,7 @@ static int sa_ul_probe(struct platform_device *pdev)
 destroy_dma_pool:
 	dma_pool_destroy(dev_data->sc_pool);
 
+disable_pm:
 	pm_runtime_put_sync(dev);
 	pm_runtime_disable(dev);
 
Signature · 1 line
2.53.0
author maintainer
#421 lore raw

PATCH 407/1376 crypto: rk3288 - fail ahash requests on HASH idle timeout

In reply to Greg Kroah-Hartman

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

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

From: Pengpeng Hou <[email protected]>

[ Upstream commit ae150db7826f21e8d19e54fb6243169628809c4d ]

rk_hash_run() waits for RK_CRYPTO_HASH_STS to become idle after the final DMA transfer, but ignores the poll result. If the hash engine never becomes idle, the driver still reads the digest registers and finalizes the request with the previous success value.

Store the poll result and finalize the request with the timeout error before reading the digest registers.

Fixes 37bc22159c45 ("crypto: rockchip - use read_poll_timeout")
---
 drivers/crypto/rockchip/rk3288_crypto_ahash.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/crypto/rockchip/rk3288_crypto_ahash.c +6 -1
index ba26b4db7a608..f726e53df9fed 100644
@@ -322,7 +322,12 @@ static int rk_hash_run(struct crypto_engine *engine, void *breq)
 	 * efficiency, and make it response quickly when dma
 	 * complete.
 	 */
-	readl_poll_timeout(rkc->reg + RK_CRYPTO_HASH_STS, v, v == 0, 10, 1000);
+	err = readl_poll_timeout(rkc->reg + RK_CRYPTO_HASH_STS, v,
+				 v == 0, 10, 1000);
+	if (err) {
+		dev_err(rkc->dev, "HASH idle timeout\n");
+		goto theend;
+	}
 
 	for (i = 0; i < crypto_ahash_digestsize(tfm) / 4; i++) {
 		v = readl(rkc->reg + RK_CRYPTO_HASH_DOUT_0 + i * 4);
Signature · 1 line
2.53.0
author maintainer
#422 lore raw

PATCH 408/1376 crypto: keembay - Fix AEAD unregister count in error path

In reply to Greg Kroah-Hartman

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

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

From: Myeonghun Pak <[email protected]>

[ Upstream commit e264401ce4776a288524e5b87593d4d864147115 ]

register_aes_algs() registers the AEAD algorithms before registering the skcipher algorithms. If skcipher registration fails, the function unwinds the earlier AEAD registration with crypto_engine_unregister_aeads(), but it passes ARRAY_SIZE(algs), which is the skcipher table size.

Use ARRAY_SIZE(algs_aead) for the AEAD unwind path so the unregister helper iterates over the same table that was registered. Also clarify the nearby
comment: the crypto registration helpers clean up algorithms registered within the same call, while this function must still unwind earlier successful registration steps.

Fixes 885743324513 ("crypto: keembay - Add support for Keem Bay OCS AES/SM4")
---
 drivers/crypto/intel/keembay/keembay-ocs-aes-core.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/crypto/intel/keembay/keembay-ocs-aes-core.c +2 -2
index 9b2d098e5eb2c..a02a75bd29860 100644
@@ -1541,7 +1541,7 @@ static int register_aes_algs(struct ocs_aes_dev *aes_dev)
 
 	/*
 	 * If any algorithm fails to register, all preceding algorithms that
-	 * were successfully registered will be automatically unregistered.
+	 * were registered in the same call are automatically unregistered.
 	 */
 	ret = crypto_engine_register_aeads(algs_aead, ARRAY_SIZE(algs_aead));
 	if (ret)
@@ -1549,7 +1549,7 @@ static int register_aes_algs(struct ocs_aes_dev *aes_dev)
 
 	ret = crypto_engine_register_skciphers(algs, ARRAY_SIZE(algs));
 	if (ret)
-		crypto_engine_unregister_aeads(algs_aead, ARRAY_SIZE(algs));
+		crypto_engine_unregister_aeads(algs_aead, ARRAY_SIZE(algs_aead));
 
 	return ret;
 }
Signature · 1 line
2.53.0
author maintainer
#423 lore raw

PATCH 409/1376 nvme-apple: Use acquire/release for queue enabled state

In reply to Greg Kroah-Hartman

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

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

From: Gui-Dong Han <[email protected]>

[ Upstream commit f61c934aa084b7440fec681be3f4b481eb5a8609 ]

apple_nvme_init_queue() initializes queue state and then marks the queue enabled. The interrupt and request paths check enabled before using that queue state.

The old wmb() after WRITE_ONCE(enabled, true) does not publish the earlier initialization before enabled becomes visible. Use a release store when enabling the queue and acquire loads when testing it.

Although the shutdown-side enabled accesses are not used for publishing queue initialization, use helpers for them as well for consistency.

Fixes 5bd2927aceba ("nvme-apple: Add initial Apple SoC NVMe driver")
---
 drivers/nvme/host/apple.c | 30 +++++++++++++++++++++++-------
 1 file changed, 23 insertions(+), 7 deletions(-)
drivers/nvme/host/apple.c +23 -7
index 839c6737dbb6b..a83721ec22993 100644
@@ -149,6 +149,23 @@ struct apple_nvme_queue {
 	bool enabled;
 };
 
+static inline bool apple_nvme_queue_enabled(struct apple_nvme_queue *q)
+{
+	/* Pair with apple_nvme_enable_queue(). */
+	return smp_load_acquire(&q->enabled);
+}
+
+static inline void apple_nvme_enable_queue(struct apple_nvme_queue *q)
+{
+	/* Publish queue initialization before setting q->enabled. */
+	smp_store_release(&q->enabled, true);
+}
+
+static inline void apple_nvme_disable_queue(struct apple_nvme_queue *q)
+{
+	WRITE_ONCE(q->enabled, false);
+}
+
 /*
  * The apple_nvme_iod describes the data in an I/O.
  *
@@ -645,7 +662,7 @@ static bool apple_nvme_handle_cq(struct apple_nvme_queue *q, bool force)
 	bool found;
 	DEFINE_IO_COMP_BATCH(iob);
 
-	if (!READ_ONCE(q->enabled) && !force)
+	if (!apple_nvme_queue_enabled(q) && !force)
 		return false;
 
 	found = apple_nvme_poll_cq(q, &iob);
@@ -748,7 +765,7 @@ static blk_status_t apple_nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
 	 * We should not need to do this, but we're still using this to
 	 * ensure we can drain requests on a dying queue.
 	 */
-	if (unlikely(!READ_ONCE(q->enabled)))
+	if (unlikely(!apple_nvme_queue_enabled(q)))
 		return BLK_STS_IOERR;
 
 	if (!nvme_check_ready(&anv->ctrl, req, true))
@@ -826,7 +843,7 @@ static void apple_nvme_disable(struct apple_nvme *anv, bool shutdown)
 	nvme_quiesce_io_queues(&anv->ctrl);
 
 	if (!dead) {
-		if (READ_ONCE(anv->ioq.enabled)) {
+		if (apple_nvme_queue_enabled(&anv->ioq)) {
 			apple_nvme_remove_sq(anv);
 			apple_nvme_remove_cq(anv);
 		}
@@ -850,8 +867,8 @@ static void apple_nvme_disable(struct apple_nvme *anv, bool shutdown)
 		nvme_disable_ctrl(&anv->ctrl, false);
 	}
 
-	WRITE_ONCE(anv->ioq.enabled, false);
-	WRITE_ONCE(anv->adminq.enabled, false);
+	apple_nvme_disable_queue(&anv->ioq);
+	apple_nvme_disable_queue(&anv->adminq);
 	mb(); /* ensure that nvme_queue_rq() sees that enabled is cleared */
 	nvme_quiesce_admin_queue(&anv->ctrl);
 
@@ -976,8 +993,7 @@ static void apple_nvme_init_queue(struct apple_nvme_queue *q)
 	memset(q->tcbs, 0,
 	       APPLE_ANS_MAX_QUEUE_DEPTH * sizeof(struct apple_nvmmu_tcb));
 	memset(q->cqes, 0, depth * sizeof(struct nvme_completion));
-	WRITE_ONCE(q->enabled, true);
-	wmb(); /* ensure the first interrupt sees the initialization */
+	apple_nvme_enable_queue(q);
 }
 
 static void apple_nvme_reset_work(struct work_struct *work)
Signature · 1 line
2.53.0
author maintainer
#424 lore raw

PATCH 410/1376 nvmet-rdma: factor out response resource cleanup

In reply to Greg Kroah-Hartman

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

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

From: Shin'ichiro Kawasaki <[email protected]>

[ Upstream commit 90096175473f7c86e39c3f74f10343f965f5a05d ]

Move the RDMA read/write context teardown and the request SGL freeing out of nvmet_rdma_release_rsp() into a new helper function nvmet_rdma_free_rsp_resources().

This is a refactoring with no functional change, in preparation for the following patch that uses nvmet_rdma_free_rsp_resources().

Stable-dep-of: 0114dd303b37 ("nvmet-rdma: fix response resource leak on queue teardown")

---
 drivers/nvme/target/rdma.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)
drivers/nvme/target/rdma.c +10 -3
index eb971feece0fd..f8574eecd2c71 100644
@@ -658,18 +658,25 @@ static void nvmet_rdma_rw_ctx_destroy(struct nvmet_rdma_rsp *rsp)
 				    req->sg, req->sg_cnt, nvmet_data_dir(req));
 }
 
-static void nvmet_rdma_release_rsp(struct nvmet_rdma_rsp *rsp)
+static void nvmet_rdma_free_rsp_resources(struct nvmet_rdma_rsp *rsp)
 {
 	struct nvmet_rdma_queue *queue = rsp->queue;
 
-	atomic_add(1 + rsp->n_rdma, &queue->sq_wr_avail);
-
 	if (rsp->n_rdma)
 		nvmet_rdma_rw_ctx_destroy(rsp);
 
 	if (rsp->req.sg < rsp->cmd->inline_sg ||
 	    rsp->req.sg >= rsp->cmd->inline_sg + queue->dev->inline_page_count)
 		nvmet_req_free_sgls(&rsp->req);
+}
+
+static void nvmet_rdma_release_rsp(struct nvmet_rdma_rsp *rsp)
+{
+	struct nvmet_rdma_queue *queue = rsp->queue;
+
+	atomic_add(1 + rsp->n_rdma, &queue->sq_wr_avail);
+
+	nvmet_rdma_free_rsp_resources(rsp);
 
 	if (unlikely(!list_empty_careful(&queue->rsp_wr_wait_list)))
 		nvmet_rdma_process_wr_wait_list(queue);
Signature · 1 line
2.53.0
author maintainer
#425 lore raw

PATCH 411/1376 nvmet-rdma: fix response resource leak on queue teardown

In reply to Greg Kroah-Hartman

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

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

From: Shin'ichiro Kawasaki <[email protected]>

[ Upstream commit 0114dd303b373522dea06053aabae34bdd33a7c4 ]

When an nvme target with rdma transport is removed while I/Os are in flight, a response can be posted but its send completion is never delivered before the connection is torn down. As a result nvmet_rdma_send_done() and nvmet_rdma_release_rsp() are never called for the response, and this leaks the allocated RDMA read/write context and request SGLs.

These leaks are recreated by running blktests nvme/061 with the rdma transport and the siw driver. Kernel kmemleak feature reports them as follows:

unreferenced object 0xffff88812bc490c0 (size 32):

    comm "kworker/2:1H", pid 409, jiffies 4307744490
    backtrace (crc 89afd339):
      __kmalloc_noprof+0x5f9/0x890
      sgl_alloc_order+0x7b/0x380
      nvmet_req_alloc_sgls+0x290/0x4f0 [nvmet]
      nvmet_rdma_map_sgl_keyed+0x241/0x12e0 [nvmet_rdma]
      nvmet_rdma_handle_command+0x73e/0xb80 [nvmet_rdma]
      __ib_process_cq+0x149/0x4c0 [ib_core]
      ib_cq_poll_work+0x49/0x160 [ib_core]
      process_one_work+0x8b2/0x1640
      worker_thread+0x5fd/0xfe0
      kthread+0x367/0x460
      ret_from_fork+0x655/0x9d0
      ret_from_fork_asm+0x1a/0x30

unreferenced object 0xffff88814bd05e80 (size 64):

    comm "kworker/3:1H", pid 148, jiffies 4295195428
    backtrace (crc e35510cb):
      __kmalloc_noprof+0x5f9/0x890
      rdma_rw_ctx_init+0x333/0x1fa0 [ib_core]
      nvmet_rdma_map_sgl_keyed+0x5c8/0x12e0 [nvmet_rdma]
      nvmet_rdma_handle_command+0x73e/0xb80 [nvmet_rdma]
      __ib_process_cq+0x149/0x4c0 [ib_core]
      ib_cq_poll_work+0x49/0x160 [ib_core]
      process_one_work+0x8b2/0x1640
      worker_thread+0x5fd/0xfe0
      kthread+0x367/0x460
      ret_from_fork+0x655/0x9d0
      ret_from_fork_asm+0x1a/0x30

To avoid the memory leaks, reclaim the memory of the in-flight responses when the queue QP is torn down. Call nvmet_rdma_free_rsp_resources() that frees up the RDMA read/write context and the request SGLs of such responses.

Fixes 8f000cac6e7a ("nvmet-rdma: add a NVMe over Fabrics RDMA target driver")
---
 drivers/nvme/target/rdma.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
drivers/nvme/target/rdma.c +18 -0
index f8574eecd2c71..36eb26c5a05d2 100644
@@ -1347,9 +1347,27 @@ static int nvmet_rdma_create_queue_ib(struct nvmet_rdma_queue *queue)
 	goto out;
 }
 
+static bool nvmet_rdma_reclaim_rsp(struct sbitmap *sb, unsigned int bitnr,
+				   void *data)
+{
+	struct nvmet_rdma_queue *queue = data;
+
+	nvmet_rdma_free_rsp_resources(&queue->rsps[bitnr]);
+
+	return true;
+}
+
 static void nvmet_rdma_destroy_queue_ib(struct nvmet_rdma_queue *queue)
 {
 	ib_drain_qp(queue->qp);
+
+	/*
+	 * Reclaim resources of a response that is still in-flight when the
+	 * queue is being torn down. This happens when the connection was
+	 * forcefully disconnected while an I/O is in flight.
+	 */
+	sbitmap_for_each_set(&queue->rsp_tags, nvmet_rdma_reclaim_rsp, queue);
+
 	if (queue->cm_id)
 		rdma_destroy_id(queue->cm_id);
 	ib_destroy_qp(queue->qp);
Signature · 1 line
2.53.0
author maintainer
#426 lore raw

PATCH 412/1376 bus: ti-sysc: Fix /chosen node reference leak

In reply to Greg Kroah-Hartman

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

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

From: Yuho Choi <[email protected]>

[ Upstream commit 6342de0aed216b6df460b492ddb532b3e0ed16f1 ]

sysc_init_stdout_path() gets the /chosen node with of_find_node_by_path() to read stdout-path. The function then overwrites the local node pointer with the stdout-path lookup result, or exits on error, without dropping the /chosen reference.

Keep the /chosen node in a separate variable and put it after the stdout-path value has been used for the lookup. The successful stdout node lookup remains referenced by the cached stdout_path pointer.

Fixes 3bb37c8e6e6a ("bus: ti-sysc: Handle stdout-path for debug console")
---
 drivers/bus/ti-sysc.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/bus/ti-sysc.c +8 -4
index 27149eb29afb2..382f7bc2e1eb4 100644
@@ -682,6 +682,7 @@ static struct device_node *stdout_path;
 
 static void sysc_init_stdout_path(struct sysc *ddata)
 {
+	struct device_node *chosen;
 	struct device_node *np = NULL;
 	const char *uart;
 
@@ -691,15 +692,18 @@ static void sysc_init_stdout_path(struct sysc *ddata)
 	if (stdout_path)
 		return;
 
-	np = of_find_node_by_path("/chosen");
-	if (!np)
+	chosen = of_find_node_by_path("/chosen");
+	if (!chosen)
 		goto err;
 
-	uart = of_get_property(np, "stdout-path", NULL);
-	if (!uart)
+	uart = of_get_property(chosen, "stdout-path", NULL);
+	if (!uart) {
+		of_node_put(chosen);
 		goto err;
+	}
 
 	np = of_find_node_by_path(uart);
+	of_node_put(chosen);
 	if (!np)
 		goto err;
 
Signature · 1 line
2.53.0
author maintainer
#427 lore raw

PATCH 413/1376 PM: sleep: Fix off-by-one in wakelocks number limit check

In reply to Greg Kroah-Hartman

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

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

From: Haowen Tu <[email protected]>

[ Upstream commit 6058646587dded0ce0ba91bd5a6afbf14fe42055 ]

CONFIG_PM_WAKELOCKS_LIMIT is documented as the maximum number of user-space wakeup sources, but the limit check is performed before the counter is incremented and only rejects new wakeup sources when the current number is greater than the limit. This allows one extra wakeup source to be created.

Reject new wakeup sources once the counter has reached the limit.

Fixes b86ff9820fd5 ("PM / Sleep: Add user space interface for manipulating wakeup sources, v3")
[ rjw: Subject edits ]
---
 kernel/power/wakelock.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/power/wakelock.c +1 -1
index 4e941999a53ba..5c2a248cf249a 100644
@@ -63,7 +63,7 @@ static unsigned int number_of_wakelocks;
 
 static inline bool wakelocks_limit_exceeded(void)
 {
-	return number_of_wakelocks > CONFIG_PM_WAKELOCKS_LIMIT;
+	return number_of_wakelocks >= CONFIG_PM_WAKELOCKS_LIMIT;
 }
 
 static inline void increment_wakelocks_number(void)
Signature · 1 line
2.53.0
author maintainer
#428 lore raw

PATCH 414/1376 cgroup/cpuset: Make nr_deadline_tasks an atomic_t

In reply to Greg Kroah-Hartman

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

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

From: Waiman Long <[email protected]>

[ Upstream commit 95220e1f18f6321008f021abc7d6f581f64bcb82 ]

The nr_deadline_tasks variable in the cpuset structure was introduced by commit 6c24849f5515 ("sched/cpuset: Keep track of SCHED_DEADLINE task in cpusets"). It is reported by sashiko [1] that nr_deadline_tasks can currently be modified by inc_dl_tasks_cs() under rq->lock and by cpuset_attach() under cpuset_mutex. So if both updates happen simultaneously, the nr_deadline_tasks variable can be corrupted leading to incorrect operations down the road.

Fix that by changing its type to atomic_t so that nr_deadline_tasks are always atomically updated. This fix patch is a low hanging fruit. It can handle some of the races between a concurrent sched_setscheduler() and cpuset_can_attach()/cpuset_attach() calls, but not all of them like the other issue raised by sashiko [2]. This will be handled hopefully in a future follow up patch.

[1] https://sashiko.dev/#/patchset/20260626181923.133658-1-longman%40redhat.com
[2] https://sashiko.dev/#/patchset/20260630033344.352702-1-longman%40redhat.com

Fixes 6c24849f5515 ("sched/cpuset: Keep track of SCHED_DEADLINE task in cpusets")
---
 kernel/cgroup/cpuset-internal.h |  2 +-
 kernel/cgroup/cpuset.c          | 10 +++++-----
 2 files changed, 6 insertions(+), 6 deletions(-)
kernel/cgroup/cpuset-internal.h +1 -1
index 383963e28ac69..6c9916e85efd1 100644
@@ -166,7 +166,7 @@ struct cpuset {
 	 * number of SCHED_DEADLINE tasks attached to this cpuset, so that we
 	 * know when to rebuild associated root domain bandwidth information.
 	 */
-	int nr_deadline_tasks;
+	atomic_t nr_deadline_tasks;
 	int nr_migrate_dl_tasks;
 	u64 sum_migrate_dl_bw;
 
kernel/cgroup/cpuset.c +5 -5
index 4bc1ea983fe79..425d1cbe73793 100644
@@ -145,14 +145,14 @@ void inc_dl_tasks_cs(struct task_struct *p)
 {
 	struct cpuset *cs = task_cs(p);
 
-	cs->nr_deadline_tasks++;
+	atomic_inc(&cs->nr_deadline_tasks);
 }
 
 void dec_dl_tasks_cs(struct task_struct *p)
 {
 	struct cpuset *cs = task_cs(p);
 
-	cs->nr_deadline_tasks--;
+	atomic_dec(&cs->nr_deadline_tasks);
 }
 
 static inline int is_partition_valid(const struct cpuset *cs)
@@ -956,7 +956,7 @@ static void dl_update_tasks_root_domain(struct cpuset *cs)
 	struct css_task_iter it;
 	struct task_struct *task;
 
-	if (cs->nr_deadline_tasks == 0)
+	if (atomic_read(&cs->nr_deadline_tasks) == 0)
 		return;
 
 	css_task_iter_start(&cs->css, 0, &it);
@@ -3142,8 +3142,8 @@ static void cpuset_attach(struct cgroup_taskset *tset)
 	cs->old_mems_allowed = cpuset_attach_nodemask_to;
 
 	if (cs->nr_migrate_dl_tasks) {
-		cs->nr_deadline_tasks += cs->nr_migrate_dl_tasks;
-		oldcs->nr_deadline_tasks -= cs->nr_migrate_dl_tasks;
+		atomic_add(cs->nr_migrate_dl_tasks, &cs->nr_deadline_tasks);
+		atomic_sub(cs->nr_migrate_dl_tasks, &oldcs->nr_deadline_tasks);
 		reset_migrate_dl_data(cs);
 	}
 
Signature · 1 line
2.53.0
author maintainer
#429 lore raw

PATCH 415/1376 arm64: dts: qcom: sm7225-fairphone-fp4: Fix address in fb node name

In reply to Greg Kroah-Hartman

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

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

From: Luca Weiss <[email protected]>

[ Upstream commit f6e65005fe55c3d09287851523de06367cbf0bc2 ]

'reg' is 0xa0000000 so the node name is missing a zero. Add it, so that the reg and address in the node name matches.

No functional impact.

Fixes 4cbea668767d ("arm64: dts: qcom: sm7225: Add device tree for Fairphone 4")
---
 arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts +1 -1
index 83dac3ca53318..2a7c5a33b5dda 100644
@@ -47,7 +47,7 @@ chosen {
 
 		stdout-path = "serial0:115200n8";
 
-		framebuffer0: framebuffer@a000000 {
+		framebuffer0: framebuffer@a0000000 {
 			compatible = "simple-framebuffer";
 			reg = <0 0xa0000000 0 (2340 * 1080 * 4)>;
 			width = <1080>;
Signature · 1 line
2.53.0
author maintainer
#430 lore raw

PATCH 416/1376 arm64: dts: qcom: hamoa: Fix clocks for HSPHYs

In reply to Greg Kroah-Hartman

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

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

From: Konrad Dybcio <[email protected]>

[ Upstream commit 115894bc201b0cd1799d239875a1b40924f0ef7b ]

The tertiary controller's HSPHY has its own toggle in TCSR, while the primary one is wired directly to the XO clock. Fix that.

---
 arch/arm64/boot/dts/qcom/x1e80100.dtsi | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/boot/dts/qcom/x1e80100.dtsi +2 -2
index 7e9de1b7c7a31..d456190ed76d4 100644
@@ -2596,7 +2596,7 @@ usb_1_ss0_hsphy: phy@fd3000 {
 			reg = <0 0x00fd3000 0 0x154>;
 			#phy-cells = <0>;
 
-			clocks = <&tcsr TCSR_USB2_1_CLKREF_EN>;
+			clocks = <&rpmhcc RPMH_CXO_CLK>;
 			clock-names = "ref";
 
 			resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>;
@@ -2736,7 +2736,7 @@ usb_1_ss2_hsphy: phy@fde000 {
 			reg = <0 0x00fde000 0 0x154>;
 			#phy-cells = <0>;
 
-			clocks = <&tcsr TCSR_USB2_1_CLKREF_EN>;
+			clocks = <&tcsr TCSR_USB2_2_CLKREF_EN>;
 			clock-names = "ref";
 
 			resets = <&gcc GCC_QUSB2PHY_TERT_BCR>;
Signature · 1 line
2.53.0
author maintainer
#431 lore raw

PATCH 417/1376 bus: qcom-ebi2: Simplify with scoped for each OF child loop

In reply to Greg Kroah-Hartman

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

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

From: Krzysztof Kozlowski <[email protected]>

[ Upstream commit 9c252f3c8f390fae4ca09de36c9262a35ae88ace ]

Use scoped for-each loop when iterating over device nodes to make code a bit simpler.

Stable-dep-of: 64774dea5896 ("bus: qcom-ebi2: Fix clock leak on probe failure")

---
 drivers/bus/qcom-ebi2.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)
drivers/bus/qcom-ebi2.c +2 -5
index c1fef1b4bd89b..be8166565e7cc 100644
@@ -292,7 +292,6 @@ static void qcom_ebi2_setup_chipselect(struct device_node *np,
 static int qcom_ebi2_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
-	struct device_node *child;
 	struct device *dev = &pdev->dev;
 	struct resource *res;
 	void __iomem *ebi2_base;
@@ -348,15 +347,13 @@ static int qcom_ebi2_probe(struct platform_device *pdev)
 	writel(val, ebi2_base);
 
 	/* Walk over the child nodes and see what chipselects we use */
-	for_each_available_child_of_node(np, child) {
+	for_each_available_child_of_node_scoped(np, child) {
 		u32 csindex;
 
 		/* Figure out the chipselect */
 		ret = of_property_read_u32(child, "reg", &csindex);
-		if (ret) {
-			of_node_put(child);
+		if (ret)
 			return ret;
-		}
 
 		if (csindex > 5) {
 			dev_err(dev,
Signature · 1 line
2.53.0
author maintainer
#432 lore raw

PATCH 418/1376 bus: qcom-ebi2: Fix clock leak on probe failure

In reply to Greg Kroah-Hartman

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

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

From: Ruoyu Wang <[email protected]>

[ Upstream commit 64774dea58969194ea5c27fa639954e551a87024 ]

qcom_ebi2_probe() enables the EBI2X and EBI2 clocks before it walks child nodes and populates child devices. If reading a child node's reg property fails, or if of_platform_default_populate() fails, probe returns without disabling either clock.

Route those failure paths through the existing clock cleanup labels so a failed probe does not leave the clocks prepared and enabled.

---
 drivers/bus/qcom-ebi2.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/bus/qcom-ebi2.c +7 -3
index be8166565e7cc..ab00c75b9e953 100644
@@ -353,7 +353,7 @@ static int qcom_ebi2_probe(struct platform_device *pdev)
 		/* Figure out the chipselect */
 		ret = of_property_read_u32(child, "reg", &csindex);
 		if (ret)
-			return ret;
+			goto err_disable_clk;
 
 		if (csindex > 5) {
 			dev_err(dev,
@@ -372,8 +372,12 @@ static int qcom_ebi2_probe(struct platform_device *pdev)
 		have_children = true;
 	}
 
-	if (have_children)
-		return of_platform_default_populate(np, NULL, dev);
+	if (have_children) {
+		ret = of_platform_default_populate(np, NULL, dev);
+		if (ret)
+			goto err_disable_clk;
+	}
+
 	return 0;
 
 err_disable_clk:
Signature · 1 line
2.53.0
author maintainer
#433 lore raw

PATCH 419/1376 wifi: mac80211_hwsim: avoid NULL skb in stop queue drain

In reply to Greg Kroah-Hartman

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

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

From: Cen Zhang <[email protected]>

[ Upstream commit 158438cd6ad69d6dd7d871582c38baf22169fede ]

mac80211_hwsim_stop() drops any frames left in data->pending. The loop currently checks skb_queue_empty() and then dequeues separately.

That split is racy with TX status handling, which can remove a pending frame under the queue lock. If the last entry is removed after the empty check, skb_dequeue() returns NULL and the stop path passes that NULL skb to ieee80211_free_txskb().

Use skb_dequeue() as the loop condition instead. The dequeue result is the object that stop owns and frees, and a concurrent status completion that empties the queue simply makes the loop terminate.

Fixes bd18de517923 ("mac80211_hwsim: drop pending frames on stop")
Assisted-by Codex:gpt-5.5
---
 drivers/net/wireless/virtual/mac80211_hwsim.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/wireless/virtual/mac80211_hwsim.c +3 -2
index 63fae67c81622..4622cbf4f5f98 100644
@@ -2117,6 +2117,7 @@ static int mac80211_hwsim_start(struct ieee80211_hw *hw)
 static void mac80211_hwsim_stop(struct ieee80211_hw *hw, bool suspend)
 {
 	struct mac80211_hwsim_data *data = hw->priv;
+	struct sk_buff *skb;
 	int i;
 
 	data->started = false;
@@ -2124,8 +2125,8 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw, bool suspend)
 	for (i = 0; i < ARRAY_SIZE(data->link_data); i++)
 		hrtimer_cancel(&data->link_data[i].beacon_timer);
 
-	while (!skb_queue_empty(&data->pending))
-		ieee80211_free_txskb(hw, skb_dequeue(&data->pending));
+	while ((skb = skb_dequeue(&data->pending)))
+		ieee80211_free_txskb(hw, skb);
 
 	wiphy_dbg(hw->wiphy, "%s\n", __func__);
 }
Signature · 1 line
2.53.0
author maintainer
#434 lore raw

PATCH 420/1376 staging: greybus: audio: correct sscanf() return value check

In reply to Greg Kroah-Hartman

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

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

From: Alexander A. Klimov <[email protected]>

[ Upstream commit f883fa1a0a0212f63acb18c50e5f900301f3bb1e ]

manager_sysfs_add_store() passes 6 pointers to sscanf(), but required latter to return 7 which always failed the operation. I corrected it to 6.

Fixes 49b9137a6002 ("staging: greybus: audio: remove redundant slot field")
---
 drivers/staging/greybus/audio_manager_sysfs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/greybus/audio_manager_sysfs.c +1 -1
index fcd518f9540cd..ff323ca8154f3 100644
@@ -23,7 +23,7 @@ static ssize_t manager_sysfs_add_store(struct kobject *kobj,
 			desc.name, &desc.vid, &desc.pid, &desc.intf_id,
 			&desc.ip_devices, &desc.op_devices);
 
-	if (num != 7)
+	if (num != 6)
 		return -EINVAL;
 
 	num = gb_audio_manager_add(&desc);
Signature · 1 line
2.53.0
author maintainer
#435 lore raw

PATCH 421/1376 staging: sm750fb: gate dualview dataflow using g_dualview

In reply to Greg Kroah-Hartman

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

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

From: Ahmet Sezgin Duran <[email protected]>

[ Upstream commit d352778979d2eed09e266ed0f3a5e3ccd3983940 ]

In sm750fb_setup and sm750fb_set_drv functions, the dualview related code is guarded by sm750_dev->fb_count > 1 condition. That value is updated only after each framebuffer is registered, while both guards are used before any increment.

Current flow:

lynxfb_pci_probe()

    sm750fb_setup()                 // fb_count is 0
    for each fb:
      sm750fb_framebuffer_alloc()
        lynxfb_set_fbinfo()
          sm750fb_set_drv()         // fb_count is 0 or 1
        register_framebuffer()
        sm750_dev->fb_count++;      // fb_count is incremented

Thus even if dualview=1 parameter is passed down to the driver, fb_count is never > 1 at either check, so dualview dataflows are not selected and crtc->vidmem_size is never halved.

Use g_dualview global variable instead of fb_count > 1 to correctly enable dualview capabilities.

Fixes a3f92cc94c61 ("staging: sm750fb: replace dual member of sm750_dev with fb_count")
---
 drivers/staging/sm750fb/sm750.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/staging/sm750fb/sm750.c +2 -2
index 94a83ec342827..1452edab96cc9 100644
@@ -599,7 +599,7 @@ static int sm750fb_set_drv(struct lynxfb_par *par)
 	crtc = &par->crtc;
 
 	crtc->vidmem_size = sm750_dev->vidmem_size;
-	if (sm750_dev->fb_count > 1)
+	if (g_dualview)
 		crtc->vidmem_size >>= 1;
 
 	/* setup crtc and output member */
@@ -966,7 +966,7 @@ static void sm750fb_setup(struct sm750_dev *sm750_dev, char *src)
 
 NO_PARAM:
 	if (sm750_dev->revid != SM750LE_REVISION_ID) {
-		if (sm750_dev->fb_count > 1) {
+		if (g_dualview) {
 			if (swap)
 				sm750_dev->dataflow = sm750_dual_swap;
 			else
Signature · 1 line
2.53.0
author maintainer
#436 lore raw

PATCH 422/1376 staging: sm750fb: Add missing Kconfig dependency

In reply to Greg Kroah-Hartman

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

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

From: Rong Zhang <[email protected]>

[ Upstream commit da8fd33e7d6af4c069668c2d42234b969f706885 ]

The sm750 frame buffer driver depends on FB_IOMEM_FOPS, but its Kconfig somehow misses it.

Fix it by making FB_SM750 select FB_IOMEM_FOPS, as other frame buffer drivers do.

Fixes dc0ad215e5d8 ("staging/sm750fb: Initialize fb_ops with fbdev macros")
---
 drivers/staging/sm750fb/Kconfig | 1 +
 1 file changed, 1 insertion(+)
drivers/staging/sm750fb/Kconfig +1 -0
index 08bcccdd0f1c4..25fe422f55f2c 100644
@@ -6,6 +6,7 @@ config FB_SM750
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
+	select FB_IOMEM_FOPS
 	help
 	  Frame buffer driver for the Silicon Motion SM750 chip
 	  with 2D acceleration and dual head support.
Signature · 1 line
2.53.0
author maintainer
#437 lore raw

PATCH 423/1376 greybus: audio: bound the topology section sizes against the fetched size

In reply to Greg Kroah-Hartman

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

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

From: Bryam Vargas <[email protected]>

[ Upstream commit 33d8c7b794d2a30637c9d3fcb478f1d3222bef1e ]

gb_audio_gb_get_topology() fetches a topology blob of a module-supplied size, and gbaudio_tplg_parse_data() then walks it by adding the module-supplied size_dais, size_controls and size_widgets fields to form the control, widget and route section offsets. Those le32 sizes are never checked against the fetched blob, so a module reporting a small topology size but large section sizes makes the offsets point past the allocation, and parsing reads out of bounds.

Reject a topology whose section sizes do not fit within the fetched size before it is parsed.

Fixes 184992e305f1 ("greybus: audio: Add Greybus Audio Device Class Protocol helper routines")
---
 drivers/staging/greybus/audio_gb.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)
drivers/staging/greybus/audio_gb.c +13 -0
index 9d8994fdb41a2..144591f1a5128 100644
@@ -37,6 +37,19 @@ int gb_audio_gb_get_topology(struct gb_connection *connection,
 		return ret;
 	}
 
+	/*
+	 * The size_* fields are supplied by the module and are used by
+	 * gbaudio_tplg_parse_data() to compute offsets into the blob; make
+	 * sure the sections fit within the fetched topology, so walking it
+	 * cannot read out of bounds.
+	 */
+	if ((u64)le32_to_cpu(topo->size_dais) + le32_to_cpu(topo->size_controls) +
+	    le32_to_cpu(topo->size_widgets) + le32_to_cpu(topo->size_routes) >
+	    size - sizeof(*topo)) {
+		kfree(topo);
+		return -EINVAL;
+	}
+
 	*topology = topo;
 
 	return 0;
Signature · 1 line
2.53.0
author maintainer
#438 lore raw

PATCH 424/1376 staging: fbtft: Use sysfs_emit_at() to print to sysfs file

In reply to Greg Kroah-Hartman

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

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

From: Dan Carpenter <[email protected]>

[ Upstream commit 221192a784c25e28b489a7e75fabf59be4f63d57 ]

This scnprintf() uses the wrong limit. It should be "PAGE_SIZE - len" instead of just PAGE_SIZE. We're not going to hit the limit in real life since we are printing at most FBTFT_GAMMA_MAX_VALUES_TOTAL (128) u32 values, however, it's still worth fixing.

Use sysfs_emit_at() to fix this since this is a sysfs file.

---
 drivers/staging/fbtft/fbtft-sysfs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/fbtft/fbtft-sysfs.c +1 -1
index e45c90a03a903..7bd6cbf2f1e56 100644
@@ -98,7 +98,7 @@ sprintf_gamma(struct fbtft_par *par, u32 *curves, char *buf)
 	mutex_lock(&par->gamma.lock);
 	for (i = 0; i < par->gamma.num_curves; i++) {
 		for (j = 0; j < par->gamma.num_values; j++)
-			len += scnprintf(&buf[len], PAGE_SIZE,
+			len += sysfs_emit_at(buf, len,
 			     "%04x ", curves[i * par->gamma.num_values + j]);
 		buf[len - 1] = '\n';
 	}
Signature · 1 line
2.53.0
author maintainer
#439 lore raw

PATCH 425/1376 staging: octeon: add missing tasklet_kill in cvm_oct_tx_shutdown

In reply to Greg Kroah-Hartman

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

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

From: Ayush Mukkanwar <[email protected]>

[ Upstream commit b9af44b0d20b2247c4eb0ea5cfca907d643eea50 ]

The TX cleanup tasklet can be scheduled by the watchdog IRQ handler to execute cvm_oct_tx_do_cleanup. There can be a pending tasklet in the queue which might run after the cvm_oct_remove() frees net_device structures, causing a use-after-free in cvm_oct_tx_do_cleanup() as it iterates cvm_oct_device[] which is an array of netdevice pointers. Add tasklet_kill() after free_irq() to ensure the tasklet is no longer scheduled or running before teardown proceeds.

---
 drivers/staging/octeon/ethernet-tx.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/staging/octeon/ethernet-tx.c +2 -0
index bbf33b88bb7c2..e54b4a413dc40 100644
@@ -711,4 +711,6 @@ void cvm_oct_tx_shutdown(void)
 {
 	/* Free the interrupt handler */
 	free_irq(OCTEON_IRQ_TIMER1, cvm_oct_device);
+
+	tasklet_kill(&cvm_oct_tx_cleanup_tasklet);
 }
Signature · 1 line
2.53.0
author maintainer
#440 lore raw

PATCH 426/1376 staging: octeon: fix free_irq dev_id mismatch in cvm_oct_rx_shutdown

In reply to Greg Kroah-Hartman

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

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

From: Yuvraj Singh Chauhan <[email protected]>

[ Upstream commit 41db5b76eeb4cc11a1097384caba7cfc659f7293 ]

In cvm_oct_rx_initialize(), request_irq() is called with &oct_rx_group[i].napi as the dev_id:

	request_irq(oct_rx_group[i].irq, cvm_oct_do_interrupt, 0, "Ethernet",
							&oct_rx_group[i].napi);

However, cvm_oct_rx_shutdown() passes cvm_oct_device (an array of struct net_device pointers) as the dev_id to free_irq():

  free_irq(oct_rx_group[i].irq, cvm_oct_device);

Since __free_irq() matches the action to remove by comparing dev_id pointers, the mismatched cookie means the IRQ handler is never found, triggering a WARN and leaving the IRQ line permanently allocated. This prevents proper driver cleanup on module removal.

Fix the mismatch by passing &oct_rx_group[i].napi as the dev_id to free_irq(), matching what was used during request_irq().

Stable-dep-of: c0a9a8586a63 ("staging: octeon: add missing napi_disable in cvm_oct_rx_shutdown")

---
 drivers/staging/octeon/ethernet-rx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/octeon/ethernet-rx.c +1 -1
index 965330eec80a8..d0b43d50b83ce 100644
@@ -535,7 +535,7 @@ void cvm_oct_rx_shutdown(void)
 			cvmx_write_csr(CVMX_POW_WQ_INT_THRX(i), 0);
 
 		/* Free the interrupt handler */
-		free_irq(oct_rx_group[i].irq, cvm_oct_device);
+		free_irq(oct_rx_group[i].irq, &oct_rx_group[i].napi);
 
 		netif_napi_del(&oct_rx_group[i].napi);
 	}
Signature · 1 line
2.53.0
author maintainer
#441 lore raw

PATCH 427/1376 staging: octeon: ethernet-mem: replace pr_warn with dev_warn in free functions

In reply to Greg Kroah-Hartman

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

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

From: Ayush Mukkanwar <[email protected]>

[ Upstream commit be5e8d5f61b31105e0ed7f51cd591653aea5054f ]

Add struct platform_device parameter to cvm_oct_free_hw_skbuff, cvm_oct_free_hw_memory and cvm_oct_mem_empty_fpa. Replace pr_warn calls with dev_warn, using &pdev->dev for device-aware logging.

Stable-dep-of: c0a9a8586a63 ("staging: octeon: add missing napi_disable in cvm_oct_rx_shutdown")

---
 drivers/staging/octeon/ethernet-mem.c | 31 ++++++++++++++++-----------
 drivers/staging/octeon/ethernet-mem.h |  5 ++++-
 drivers/staging/octeon/ethernet.c     |  6 +++---
 3 files changed, 25 insertions(+), 17 deletions(-)
drivers/staging/octeon/ethernet-mem.c +18 -13
index 532594957ebcf..af79b2bdac278 100644
@@ -5,6 +5,7 @@
  * Copyright (c) 2003-2010 Cavium Networks
  */
 
+#include <linux/platform_device.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
 #include <linux/slab.h>
@@ -40,11 +41,13 @@ static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements)
 
 /**
  * cvm_oct_free_hw_skbuff- free hardware pool skbuffs
+ * @pdev:     Platform device for logging
  * @pool:     Pool to allocate an skbuff for
  * @size:     Size of the buffer needed for the pool
  * @elements: Number of buffers to allocate
  */
-static void cvm_oct_free_hw_skbuff(int pool, int size, int elements)
+static void cvm_oct_free_hw_skbuff(struct platform_device *pdev,
+				   int pool, int size, int elements)
 {
 	char *memory;
 
@@ -59,11 +62,11 @@ static void cvm_oct_free_hw_skbuff(int pool, int size, int elements)
 	} while (memory);
 
 	if (elements < 0)
-		pr_warn("Freeing of pool %u had too many skbuffs (%d)\n",
-			pool, elements);
+		dev_warn(&pdev->dev, "Freeing of pool %u had too many skbuffs (%d)\n",
+			 pool, elements);
 	else if (elements > 0)
-		pr_warn("Freeing of pool %u is missing %d skbuffs\n",
-			pool, elements);
+		dev_warn(&pdev->dev, "Freeing of pool %u is missing %d skbuffs\n",
+			 pool, elements);
 }
 
 /**
@@ -107,11 +110,13 @@ static int cvm_oct_fill_hw_memory(int pool, int size, int elements)
 
 /**
  * cvm_oct_free_hw_memory - Free memory allocated by cvm_oct_fill_hw_memory
+ * @pdev:     Platform device for logging
  * @pool:     FPA pool to free
  * @size:     Size of each buffer in the pool
  * @elements: Number of buffers that should be in the pool
  */
-static void cvm_oct_free_hw_memory(int pool, int size, int elements)
+static void cvm_oct_free_hw_memory(struct platform_device *pdev,
+				   int pool, int size, int elements)
 {
 	char *memory;
 	char *fpa;
@@ -127,11 +132,11 @@ static void cvm_oct_free_hw_memory(int pool, int size, int elements)
 	} while (fpa);
 
 	if (elements < 0)
-		pr_warn("Freeing of pool %u had too many buffers (%d)\n",
-			pool, elements);
+		dev_warn(&pdev->dev, "Freeing of pool %u had too many buffers (%d)\n",
+			 pool, elements);
 	else if (elements > 0)
-		pr_warn("Warning: Freeing of pool %u is missing %d buffers\n",
-			pool, elements);
+		dev_warn(&pdev->dev, "Freeing of pool %u is missing %d buffers\n",
+			 pool, elements);
 }
 
 int cvm_oct_mem_fill_fpa(int pool, int size, int elements)
@@ -145,10 +150,10 @@ int cvm_oct_mem_fill_fpa(int pool, int size, int elements)
 	return freed;
 }
 
-void cvm_oct_mem_empty_fpa(int pool, int size, int elements)
+void cvm_oct_mem_empty_fpa(struct platform_device *pdev, int pool, int size, int elements)
 {
 	if (pool == CVMX_FPA_PACKET_POOL)
-		cvm_oct_free_hw_skbuff(pool, size, elements);
+		cvm_oct_free_hw_skbuff(pdev, pool, size, elements);
 	else
-		cvm_oct_free_hw_memory(pool, size, elements);
+		cvm_oct_free_hw_memory(pdev, pool, size, elements);
 }
drivers/staging/octeon/ethernet-mem.h +4 -1
index 692dcdb7154da..ff10ba4525ee8 100644
@@ -6,4 +6,7 @@
  */
 
 int cvm_oct_mem_fill_fpa(int pool, int size, int elements);
-void cvm_oct_mem_empty_fpa(int pool, int size, int elements);
+struct platform_device;
+
+void cvm_oct_mem_empty_fpa(struct platform_device *pdev, int pool, int size,
+			   int elements);
drivers/staging/octeon/ethernet.c +3 -3
index a5e99cc78a454..4fb2967598527 100644
@@ -958,12 +958,12 @@ static void cvm_oct_remove(struct platform_device *pdev)
 	cvmx_ipd_free_ptr();
 
 	/* Free the HW pools */
-	cvm_oct_mem_empty_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE,
+	cvm_oct_mem_empty_fpa(pdev, CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE,
 			      num_packet_buffers);
-	cvm_oct_mem_empty_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE,
+	cvm_oct_mem_empty_fpa(pdev, CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE,
 			      num_packet_buffers);
 	if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL)
-		cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL,
+		cvm_oct_mem_empty_fpa(pdev, CVMX_FPA_OUTPUT_BUFFER_POOL,
 				      CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128);
 }
 
Signature · 1 line
2.53.0
author maintainer
#442 lore raw

PATCH 428/1376 staging: octeon: replace pr_warn with dev_warn in fill and rx paths

In reply to Greg Kroah-Hartman

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

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

From: Ayush Mukkanwar <[email protected]>

[ Upstream commit 2191a8dfd1f5a3091e9f388899beb137686c6532 ]

Add struct platform_device parameter to cvm_oct_fill_hw_memory, cvm_oct_mem_fill_fpa, cvm_oct_rx_refill_pool and cvm_oct_rx_initialize to support device-aware logging. Replace pr_warn with dev_warn using &pdev->dev.
To avoid passing these parameters through global state, introduce struct octeon_ethernet_platform to hold per-device state including the rx_refill_work and the oct_rx_group array. This ensures all receive group state and workers are correctly associated with the platform device.
Define struct oct_rx_group and struct octeon_ethernet_platform in octeon-ethernet.h so they are shared across compilation units.

Stable-dep-of: c0a9a8586a63 ("staging: octeon: add missing napi_disable in cvm_oct_rx_shutdown")

---
 drivers/staging/octeon/ethernet-mem.c    | 12 +++---
 drivers/staging/octeon/ethernet-mem.h    |  3 +-
 drivers/staging/octeon/ethernet-rx.c     | 49 ++++++++++++------------
 drivers/staging/octeon/ethernet-rx.h     | 11 ++++--
 drivers/staging/octeon/ethernet.c        | 37 +++++++++++-------
 drivers/staging/octeon/octeon-ethernet.h | 14 +++++++
 6 files changed, 78 insertions(+), 48 deletions(-)
drivers/staging/octeon/ethernet-mem.c +7 -5
index af79b2bdac278..68c3ef984e565 100644
@@ -71,13 +71,15 @@ static void cvm_oct_free_hw_skbuff(struct platform_device *pdev,
 
 /**
  * cvm_oct_fill_hw_memory - fill a hardware pool with memory.
+ * @pdev:     Platform device for logging
  * @pool:     Pool to populate
  * @size:     Size of each buffer in the pool
  * @elements: Number of buffers to allocate
  *
  * Returns the actual number of buffers allocated.
  */
-static int cvm_oct_fill_hw_memory(int pool, int size, int elements)
+static int cvm_oct_fill_hw_memory(struct platform_device *pdev, int pool, int size,
+				  int elements)
 {
 	char *memory;
 	char *fpa;
@@ -96,8 +98,8 @@ static int cvm_oct_fill_hw_memory(int pool, int size, int elements)
 		 */
 		memory = kmalloc(size + 256, GFP_ATOMIC);
 		if (unlikely(!memory)) {
-			pr_warn("Unable to allocate %u bytes for FPA pool %d\n",
-				elements * size, pool);
+			dev_warn(&pdev->dev, "Unable to allocate %u bytes for FPA pool %d\n",
+				 elements * size, pool);
 			break;
 		}
 		fpa = (char *)(((unsigned long)memory + 256) & ~0x7fUL);
@@ -139,14 +141,14 @@ static void cvm_oct_free_hw_memory(struct platform_device *pdev,
 			 pool, elements);
 }
 
-int cvm_oct_mem_fill_fpa(int pool, int size, int elements)
+int cvm_oct_mem_fill_fpa(struct platform_device *pdev, int pool, int size, int elements)
 {
 	int freed;
 
 	if (pool == CVMX_FPA_PACKET_POOL)
 		freed = cvm_oct_fill_hw_skbuff(pool, size, elements);
 	else
-		freed = cvm_oct_fill_hw_memory(pool, size, elements);
+		freed = cvm_oct_fill_hw_memory(pdev, pool, size, elements);
 	return freed;
 }
 
drivers/staging/octeon/ethernet-mem.h +2 -1
index ff10ba4525ee8..9279bb0de2db4 100644
@@ -5,8 +5,9 @@
  * Copyright (c) 2003-2007 Cavium Networks
  */
 
-int cvm_oct_mem_fill_fpa(int pool, int size, int elements);
 struct platform_device;
 
+int cvm_oct_mem_fill_fpa(struct platform_device *pdev, int pool, int size,
+			 int elements);
 void cvm_oct_mem_empty_fpa(struct platform_device *pdev, int pool, int size,
 			   int elements);
drivers/staging/octeon/ethernet-rx.c +25 -24

125 lines not on this page · raw message

drivers/staging/octeon/ethernet-rx.h +7 -4
index ff6482fa20d69..6093694326cb6 100644
@@ -5,11 +5,14 @@
  * Copyright (c) 2003-2007 Cavium Networks
  */
 
+struct platform_device;
+
 void cvm_oct_poll_controller(struct net_device *dev);
-void cvm_oct_rx_initialize(void);
-void cvm_oct_rx_shutdown(void);
+void cvm_oct_rx_initialize(struct platform_device *pdev);
+void cvm_oct_rx_shutdown(struct platform_device *pdev);
 
-static inline void cvm_oct_rx_refill_pool(int fill_threshold)
+static inline void cvm_oct_rx_refill_pool(struct platform_device *pdev,
+					  int fill_threshold)
 {
 	int number_to_free;
 	int num_freed;
@@ -20,7 +23,7 @@ static inline void cvm_oct_rx_refill_pool(int fill_threshold)
 	if (number_to_free > fill_threshold) {
 		cvmx_fau_atomic_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE,
 				      -number_to_free);
-		num_freed = cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL,
+		num_freed = cvm_oct_mem_fill_fpa(pdev, CVMX_FPA_PACKET_POOL,
 						 CVMX_FPA_PACKET_POOL_SIZE,
 						 number_to_free);
 		if (num_freed != number_to_free) {
drivers/staging/octeon/ethernet.c +23 -14
index 4fb2967598527..b8a528881fca5 100644
@@ -104,11 +104,10 @@ struct net_device *cvm_oct_device[TOTAL_NUMBER_OF_PORTS];
 
 u64 cvm_oct_tx_poll_interval;
 
-static void cvm_oct_rx_refill_worker(struct work_struct *work);
-static DECLARE_DELAYED_WORK(cvm_oct_rx_refill_work, cvm_oct_rx_refill_worker);
-
 static void cvm_oct_rx_refill_worker(struct work_struct *work)
 {
+	struct octeon_ethernet_platform *plat = container_of(work,
+		struct octeon_ethernet_platform, rx_refill_work.work);
 	/*
 	 * FPA 0 may have been drained, try to refill it if we need
 	 * more than num_packet_buffers / 2, otherwise normal receive
@@ -116,10 +115,10 @@ static void cvm_oct_rx_refill_worker(struct work_struct *work)
 	 * could be received so cvm_oct_napi_poll would never be
 	 * invoked to do the refill.
 	 */
-	cvm_oct_rx_refill_pool(num_packet_buffers / 2);
+	cvm_oct_rx_refill_pool(plat->pdev, num_packet_buffers / 2);
 
 	if (!atomic_read(&cvm_oct_poll_queue_stopping))
-		schedule_delayed_work(&cvm_oct_rx_refill_work, HZ);
+		schedule_delayed_work(&plat->rx_refill_work, HZ);
 }
 
 static void cvm_oct_periodic_worker(struct work_struct *work)
@@ -138,16 +137,16 @@ static void cvm_oct_periodic_worker(struct work_struct *work)
 		schedule_delayed_work(&priv->port_periodic_work, HZ);
 }
 
-static void cvm_oct_configure_common_hw(void)
+static void cvm_oct_configure_common_hw(struct platform_device *pdev)
 {
 	/* Setup the FPA */
 	cvmx_fpa_enable();
-	cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE,
+	cvm_oct_mem_fill_fpa(pdev, CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE,
 			     num_packet_buffers);
-	cvm_oct_mem_fill_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE,
+	cvm_oct_mem_fill_fpa(pdev, CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE,
 			     num_packet_buffers);
 	if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL)
-		cvm_oct_mem_fill_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL,
+		cvm_oct_mem_fill_fpa(pdev, CVMX_FPA_OUTPUT_BUFFER_POOL,
 				     CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 1024);
 
 #ifdef __LITTLE_ENDIAN
@@ -678,6 +677,15 @@ static int cvm_oct_probe(struct platform_device *pdev)
 	int qos;
 	struct device_node *pip;
 	int mtu_overhead = ETH_HLEN + ETH_FCS_LEN;
+	struct octeon_ethernet_platform *plat;
+
+	plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
+	if (!plat)
+		return -ENOMEM;
+
+	plat->pdev = pdev;
+	INIT_DELAYED_WORK(&plat->rx_refill_work, cvm_oct_rx_refill_worker);
+	platform_set_drvdata(pdev, plat);
 
 #if IS_ENABLED(CONFIG_VLAN_8021Q)
 	mtu_overhead += VLAN_HLEN;
@@ -689,7 +697,7 @@ static int cvm_oct_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	cvm_oct_configure_common_hw();
+	cvm_oct_configure_common_hw(pdev);
 
 	cvmx_helper_initialize_packet_io_global();
 
@@ -912,28 +920,29 @@ static int cvm_oct_probe(struct platform_device *pdev)
 	}
 
 	cvm_oct_tx_initialize();
-	cvm_oct_rx_initialize();
+	cvm_oct_rx_initialize(pdev);
 
 	/*
 	 * 150 uS: about 10 1500-byte packets at 1GE.
 	 */
 	cvm_oct_tx_poll_interval = 150 * (octeon_get_clock_rate() / 1000000);
 
-	schedule_delayed_work(&cvm_oct_rx_refill_work, HZ);
+	schedule_delayed_work(&plat->rx_refill_work, HZ);
 
 	return 0;
 }
 
 static void cvm_oct_remove(struct platform_device *pdev)
 {
+	struct octeon_ethernet_platform *plat = platform_get_drvdata(pdev);
 	int port;
 
 	cvmx_ipd_disable();
 
 	atomic_inc_return(&cvm_oct_poll_queue_stopping);
-	cancel_delayed_work_sync(&cvm_oct_rx_refill_work);
+	cancel_delayed_work_sync(&plat->rx_refill_work);
 
-	cvm_oct_rx_shutdown();
+	cvm_oct_rx_shutdown(pdev);
 	cvm_oct_tx_shutdown();
 
 	cvmx_pko_disable();
drivers/staging/octeon/octeon-ethernet.h +14 -0
index a6140705706f4..0ac430db1e6eb 100644
@@ -11,6 +11,7 @@
 #ifndef OCTEON_ETHERNET_H
 #define OCTEON_ETHERNET_H
 
+#include <linux/netdevice.h>
 #include <linux/of.h>
 #include <linux/phy.h>
 
@@ -74,6 +75,19 @@ struct octeon_ethernet {
 	struct device_node	*of_node;
 };
 
+struct oct_rx_group {
+	int irq;
+	int group;
+	struct napi_struct napi;
+	struct platform_device *pdev;
+};
+
+struct octeon_ethernet_platform {
+	struct platform_device *pdev;
+	struct delayed_work rx_refill_work;
+	struct oct_rx_group rx_group[16];
+};
+
 int cvm_oct_free_work(void *work_queue_entry);
 
 int cvm_oct_rgmii_open(struct net_device *dev);
Signature · 1 line
2.53.0
author maintainer
#443 lore raw

PATCH 429/1376 staging: octeon: add missing napi_disable in cvm_oct_rx_shutdown

In reply to Greg Kroah-Hartman

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

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

From: Ayush Mukkanwar <[email protected]>

[ Upstream commit c0a9a8586a63fda49e61a6b83360feac2a60d898 ]

cvm_oct_rx_shutdown calls free_irq and netif_napi_del without disabling the napi instance first. As the free_irq only waits for completion of hard interrupt handlers, the napi poll function could still be active. If cvm_oct_remove proceeds to free the plat structure (which holds the NAPI instances), the active poll function will access freed memory, resulting in a use-after-free crash.

---
 drivers/staging/octeon/ethernet-rx.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/staging/octeon/ethernet-rx.c +2 -0
index cd36b5ba6f6c2..3e9d58d321560 100644
@@ -535,6 +535,8 @@ void cvm_oct_rx_shutdown(struct platform_device *pdev)
 		else
 			cvmx_write_csr(CVMX_POW_WQ_INT_THRX(i), 0);
 
+		napi_disable(&plat->rx_group[i].napi);
+
 		/* Free the interrupt handler */
 		free_irq(plat->rx_group[i].irq, &plat->rx_group[i].napi);
 
Signature · 1 line
2.53.0
author maintainer
#444 lore raw

PATCH 430/1376 staging: rtl8723bs: fix mismatched free of HalData in rtw_sdio_if1_init()

In reply to Greg Kroah-Hartman

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

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

From: Dawei Feng <[email protected]>

[ Upstream commit 264676418b726baca7be49171e306b6aa05cceb0 ]

padapter->HalData is allocated via vzalloc(), but incorrectly freed using kfree() in the rtw_sdio_if1_init() error path. Using kfree() to release this vmalloc-backed buffer can lead to memory corruption.

Use rtw_hal_data_deinit() to pair the free correctly and free HalData with vfree().

The bug was first flagged by an experimental static analysis tool we are developing for kernel memory-management bugs. Manual inspection confirms that the issue is still present in current mainline.

An x86_64 allyesconfig build showed no new warnings. As we do not have suitable RTL8723BS SDIO hardware to test with, no runtime testing was able to be performed.

---
 drivers/staging/rtl8723bs/os_dep/sdio_intf.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/staging/rtl8723bs/os_dep/sdio_intf.c +2 -2
index d64998be6b2bb..c9a90d5293b02 100644
@@ -309,8 +309,8 @@ static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct
 	status = _SUCCESS;
 
 free_hal_data:
-	if (status != _SUCCESS && padapter->HalData)
-		kfree(padapter->HalData);
+	if (status != _SUCCESS)
+		rtw_hal_data_deinit(padapter);
 
 	if (status != _SUCCESS) {
 		rtw_wdev_unregister(padapter->rtw_wdev);
Signature · 1 line
2.53.0
author maintainer
#445 lore raw

PATCH 431/1376 ALSA: via82xx: Remove unreachable branch in snd_via686_pcm_pointer()

In reply to Greg Kroah-Hartman

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

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

From: Evgenii Burenchev <[email protected]>

[ Upstream commit cd3447e1b6425efd1704ed07f1f245c842927eb0 ]

The condition

	if (count && size < count)

can never evaluate to true.

The VIA DMA count register is masked with 0x00ffffff before use, while the DMA buffer size is limited to 0x00fffffe bytes. As a result, 'count' can never exceed 'size', making the condition permanently false.

This branch has therefore been unreachable since the driver was introduced. Remove the unreachable branch without changing runtime behavior.

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

---
 sound/pci/via82xx_modem.c | 26 ++++++++++----------------
 1 file changed, 10 insertions(+), 16 deletions(-)
sound/pci/via82xx_modem.c +10 -16
index a0a49b8d15116..60235e953a62d 100644
@@ -576,24 +576,18 @@ static inline unsigned int calc_linear_pos(struct via82xx_modem *chip,
 		       viadev->bufsize2, viadev->idx_table[idx].offset,
 		       viadev->idx_table[idx].size, count);
 #endif
-		if (count && size < count) {
+		if (! count)
+			/* bogus count 0 on the DMA boundary? */
+			res = viadev->idx_table[idx].offset;
+		else
+			/* count register returns full size
+			 * when end of buffer is reached
+			 */
+			res = viadev->idx_table[idx].offset + size;
+		if (check_invalid_pos(viadev, res)) {
 			dev_dbg(chip->card->dev,
-				"invalid via82xx_cur_ptr, using last valid pointer\n");
+				"invalid via82xx_cur_ptr (2), using last valid pointer\n");
 			res = viadev->lastpos;
-		} else {
-			if (! count)
-				/* bogus count 0 on the DMA boundary? */
-				res = viadev->idx_table[idx].offset;
-			else
-				/* count register returns full size
-				 * when end of buffer is reached
-				 */
-				res = viadev->idx_table[idx].offset + size;
-			if (check_invalid_pos(viadev, res)) {
-				dev_dbg(chip->card->dev,
-					"invalid via82xx_cur_ptr (2), using last valid pointer\n");
-				res = viadev->lastpos;
-			}
 		}
 	}
 	viadev->lastpos = res; /* remember the last position */
Signature · 1 line
2.53.0
author maintainer
#446 lore raw

PATCH 432/1376 selftests/bpf: Fix memory leak in msg_alloc_iov error path

In reply to Greg Kroah-Hartman

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

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

From: Malaya Kumar Rout <[email protected]>

[ Upstream commit 0bebfaa39deadec21638f6fba553eae12627a26d ]

In msg_alloc_iov(), when calloc() fails for an individual iov_base allocation, the error path frees all previously allocated iov_base entries but fails to free the iov array itself that was allocated with calloc() at the beginning of the function. This results in a memory leak of the iov array.

Add free(iov) in the unwind_iov error path to ensure proper cleanup of all allocated memory.

---
 tools/testing/selftests/bpf/test_sockmap.c | 1 +
 1 file changed, 1 insertion(+)
tools/testing/selftests/bpf/test_sockmap.c +1 -0
index 61a747afcd05f..a45c96e92a42f 100644
@@ -515,6 +515,7 @@ static int msg_alloc_iov(struct msghdr *msg,
 unwind_iov:
 	for (i--; i >= 0 ; i--)
 		free(msg->msg_iov[i].iov_base);
+	free(iov);
 	return -ENOMEM;
 }
 
Signature · 1 line
2.53.0
author maintainer
#447 lore raw

PATCH 433/1376 selftests/bpf: Fix memory leak in msg_alloc_iov

In reply to Greg Kroah-Hartman

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

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

From: Feng Yang <[email protected]>

[ Upstream commit 602701718649936eb287bf6c7ecf870ec54c6f71 ]

In the msg_alloc_iov function, the iov pointer is only assigned to msg->msg_iov after all memory allocations complete successfully. Therefore, when a calloc failure triggers the unwind_iov cleanup branch, we should use the local variable iov instead of msg->msg_iov.

Fixes 753fb2ee0934 ("bpf: sockmap, add msg_peek tests to test_sockmap")
---
 tools/testing/selftests/bpf/test_sockmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/bpf/test_sockmap.c +1 -1
index a45c96e92a42f..7b237f737624f 100644
@@ -514,7 +514,7 @@ static int msg_alloc_iov(struct msghdr *msg,
 	return 0;
 unwind_iov:
 	for (i--; i >= 0 ; i--)
-		free(msg->msg_iov[i].iov_base);
+		free(iov[i].iov_base);
 	free(iov);
 	return -ENOMEM;
 }
Signature · 1 line
2.53.0
author maintainer
#448 lore raw

PATCH 434/1376 selftests/lsm: Fix memory leak in attr_lsm_count

In reply to Greg Kroah-Hartman

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

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

From: Wang Yan <[email protected]>

[ Upstream commit 0cee720cfd51402cfcb14d96cb326a36c13b823a ]

The calloc-allocated buffer in attr_lsm_count() is never released on any exit path, including both the normal return path and the early return when read_sysfs_lsms fails, resulting in a heap memory leak.

Add free() for the buffer on all return branches to fix the leak.

Fixes d3d929a8b0cd ("LSM: selftests for Linux Security Module syscalls")
---
 tools/testing/selftests/lsm/common.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
tools/testing/selftests/lsm/common.c +3 -1
index 9ad258912646c..927dce4f04cb2 100644
@@ -76,7 +76,7 @@ int attr_lsm_count(void)
 		return 0;
 
 	if (read_sysfs_lsms(names, sysconf(_SC_PAGESIZE)))
-		return 0;
+		goto out;
 
 	if (strstr(names, "selinux"))
 		count++;
@@ -85,5 +85,7 @@ int attr_lsm_count(void)
 	if (strstr(names, "apparmor"))
 		count++;
 
+out:
+	free(names);
 	return count;
 }
Signature · 1 line
2.53.0
author maintainer
#449 lore raw

PATCH 435/1376 irqchip/gic-v3-its: Fix memleak in its_probe_one()

In reply to Greg Kroah-Hartman

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

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

From: Kemeng Shi <[email protected]>

[ Upstream commit 1efffab6fe336a5c4fd3c2886f255cd2f998e65f ]

Fix collection leak when its_init_domain() failed in its_probe_one().

Fixes 4c21f3c26ecc2 ("irqchip: GICv3: ITS: DT probing and initialization")
---
 drivers/irqchip/irq-gic-v3-its.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/irqchip/irq-gic-v3-its.c +3 -1
index 95d337978c75f..da9490dc14b92 100644
@@ -5216,7 +5216,7 @@ static int __init its_probe_one(struct its_node *its)
 
 	err = its_init_domain(its);
 	if (err)
-		goto out_free_tables;
+		goto out_free_collection;
 
 	raw_spin_lock(&its_lock);
 	list_add(&its->entry, &its_nodes);
@@ -5224,6 +5224,8 @@ static int __init its_probe_one(struct its_node *its)
 
 	return 0;
 
+out_free_collection:
+	kfree(its->collections);
 out_free_tables:
 	its_free_tables(its);
 out_free_cmd:
Signature · 1 line
2.53.0
author maintainer
#450 lore raw

PATCH 436/1376 irqchip/gic-v3-its: Fix its node leak in gic_acpi_parse_madt_its()

In reply to Greg Kroah-Hartman

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

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

From: Kemeng Shi <[email protected]>

[ Upstream commit 698a8648ca8051d34722b09b8a8088c741120ac3 ]

Fix its node leak when its_probe_one() failed in
gic_acpi_parse_madt_its().

Fixes 9585a495ac936 ("irqchip/gic-v3-its: Split allocation from initialisation of its_node")
---
 drivers/irqchip/irq-gic-v3-its.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +6 -2
index da9490dc14b92..7050bf88b87d3 100644
@@ -5638,9 +5638,13 @@ static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header,
 		its->flags |= ITS_FLAGS_FORCE_NON_SHAREABLE;
 
 	err = its_probe_one(its);
-	if (!err)
-		return 0;
+	if (err)
+		goto probe_err;
+
+	return 0;
 
+probe_err:
+	its_node_destroy(its);
 node_err:
 	iort_deregister_domain_token(its_entry->translation_id);
 dom_err:
Signature · 1 line
2.53.0
author maintainer
#451 lore raw

PATCH 437/1376 selftests: timers: leap-a-day: Fix -w option and update usage comment

In reply to Greg Kroah-Hartman

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

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

From: Jiangshan Yi <[email protected]>

[ Upstream commit b4b66151a71445f3a71574136ddc82968c7b175e ]

Commit 98b74e1f3104 ("kselftests: timers: leap-a-day: Change default arguments to help test runs") replaced the -s option with -w and made "wait for the leap second" the non-default behaviour, but it only updated the switch/case handling. Two things were left inconsistent:

- The getopt() option string still lists 's' instead of 'w', so passing -w is rejected as an invalid option and the new behaviour cannot be selected at all.

- The file header comment still documents the removed -s option and an outdated default for -i.

Fix the getopt() string to accept 'w' (matching the existing case 'w':
handler) and update the header comment to describe -w, -t and the current -i default.

Fixes 98b74e1f3104 ("kselftests: timers: leap-a-day: Change default arguments to help test runs")
---
 tools/testing/selftests/timers/leap-a-day.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)
tools/testing/selftests/timers/leap-a-day.c +11 -8
index 986abbdb15217..eb99683e5ced1 100644
@@ -9,16 +9,19 @@
  *  kernel's leap-second behavior, as well as how well applications
  *  handle the leap-second discontinuity.
  *
- *  Usage: leap-a-day [-s] [-i <num>]
+ *  Usage: leap-a-day [-w] [-i <num>] [-t]
  *
  *  Options:
- *	-s:	Each iteration, set the date to 10 seconds before midnight GMT.
- *		This speeds up the number of leapsecond transitions tested,
- *		but because it calls settimeofday frequently, advancing the
- *		time by 24 hours every ~16 seconds, it may cause application
- *		disruption.
+ *	-w:	Only set the leap-second flag and wait for the leap second
+ *		each iteration, instead of advancing the time. By default the
+ *		date is set to 10 seconds before midnight GMT, which speeds up
+ *		the number of leapsecond transitions tested, but because it
+ *		calls settimeofday frequently, advancing the time by 24 hours
+ *		every ~16 seconds, it may cause application disruption.
  *
- *	-i:	Number of iterations to run (default: infinite)
+ *	-i:	Number of iterations to run (-1 = infinite, default: 10)
+ *
+ *	-t:	Print TAI time.
  *
  *  Other notes: Disabling NTP prior to running this is advised, as the two
  *		 may conflict in their commands to the kernel.
@@ -186,7 +189,7 @@ int main(int argc, char **argv)
 	int opt;
 
 	/* Process arguments */
-	while ((opt = getopt(argc, argv, "sti:")) != -1) {
+	while ((opt = getopt(argc, argv, "wti:")) != -1) {
 		switch (opt) {
 		case 'w':
 			printf("Only setting leap-flag, not changing time. It could take up to a day for leap to trigger.\n");
Signature · 1 line
2.53.0
author maintainer
#452 lore raw

PATCH 438/1376 clocksource: Unregister subsystem on device registration failure

In reply to Greg Kroah-Hartman

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

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

From: Yuho Choi <[email protected]>

[ Upstream commit 3dee6537e728bd8137fda6eaf859f26e685943f7 ]

init_clocksource_sysfs() registers the clocksource subsystem before registering the clocksource device. If device_register() fails, the function returns the error while leaving the subsystem registered.

Unregister the clocksource subsystem on that failure path so the successful subsystem registration is unwound before returning.

Fixes d369a5d8fc70 ("clocksource: convert sysdev_class to a regular subsystem")
---
 kernel/time/clocksource.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
kernel/time/clocksource.c +6 -2
index df386912f9613..e69c349a2fef9 100644
@@ -1510,8 +1510,12 @@ static int __init init_clocksource_sysfs(void)
 {
 	int error = subsys_system_register(&clocksource_subsys, NULL);
 
-	if (!error)
-		error = device_register(&device_clocksource);
+	if (error)
+		return error;
+
+	error = device_register(&device_clocksource);
+	if (error)
+		bus_unregister(&clocksource_subsys);
 
 	return error;
 }
Signature · 1 line
2.53.0
author maintainer
#453 lore raw

PATCH 439/1376 y2038: uapi: Use 64-bit __kernel_old_timespec::tv_nsec on x32

In reply to Greg Kroah-Hartman

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

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

From: Thomas Weißschuh <[email protected]>

[ Upstream commit 79ced850e549e8c86b772a79ea417a1425b5c04b ]

'struct __kernel_old_timespec' represents the 'native' time ABI of the kernel. On 32-bit systems it uses 32-bit fields and on 64-bit systems it uses 64-bit fields.

However the x86 x32 ABI uses the 64-bit time ABI natively. This is correctly handled for the 'tv_sec' fields, through the typedefs of '__kernel_old_time_t' -> '__kernel_long_t' -> 'long long'. The same treatment was missed for 'tv_nsec'.

In practice this might not make much of a difference as the value of 'tv_nsec' will always fit into 32 bits and the missing bits fall into the padding of the structure.

When introspecting the structure however, a difference can be observed.

Switch to 64-bit tv_nsec on x32. No other architectures or ABIs are affected.

While this could be interpreted as violating the POSIX requirement of 'timespec::tv_nsec' being 'long':

* __kernel_old_timespec is not actually the POSIX timespec type

* the requirement is gone in newer versions of POSIX

* this matches glibc

Fixes 94c467ddb273 ("y2038: add __kernel_old_timespec and __kernel_old_time_t")
---
 include/uapi/linux/time_types.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/uapi/linux/time_types.h +1 -1
index bcc0002115d39..03a0d8aaadca5 100644
@@ -30,7 +30,7 @@ struct __kernel_old_timeval {
 
 struct __kernel_old_timespec {
 	__kernel_old_time_t	tv_sec;		/* seconds */
-	long			tv_nsec;	/* nanoseconds */
+	__kernel_long_t		tv_nsec;	/* nanoseconds */
 };
 
 struct __kernel_old_itimerval {
Signature · 1 line
2.53.0
author maintainer
#454 lore raw

PATCH 440/1376 timekeeping: Account for monotonicity adjustment in ntp_error

In reply to Greg Kroah-Hartman

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

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

From: David Woodhouse <[email protected]>

[ Upstream commit b7befd6d91207cf3f4cecd68fea0c212093906cf ]

timekeeping_apply_adjustment() modifies xtime_nsec to ensure monotonicity when mult changes:

xtime_nsec -= offset

This ensures that the time reported to userspace does not jump when the multiplier is adjusted from one tick to the next. However, the ntp_error accumulator which tracks the difference between intended and actual clock position was not being updated to reflect this additional discrepancy.

An earlier attempt at this compensation existed as:

ntp_error -= (interval - offset) << ntp_error_shift

but was removed in commit c2cda2a5bda9 ("timekeeping/ntp: Don't align NTP frequency adjustments to ticks") because it was a major source of NTP error. That's because (interval - offset) was wrong: the subtraction of "interval" prematurely accounted for the changed xtime_interval of the next tick, which would be correctly accounted in the next accumulation anyway — a double subtraction.

What is actually needed is just the "offset" part: ntp_error must be told that xtime_nsec moved by "offset" without a corresponding change in the intended position. For the normal ±1 mult dithering this is negligible (the adjustments cancel over time), but for larger mult changes — such as when an external reference clock sets a new frequency — the one-time uncompensated offset is significant.

Fix by adjusting ntp_error by the correct amount:

    ntp_error += offset << ntp_error_shift

This keeps ntp_error consistent with the actual xtime_nsec position after the adjustment, and ensures the discrepancy is correctly smoothed away over time and the clock returns to where it should have been.

Fixes c2cda2a5bda9 ("timekeeping/ntp: Don't align NTP frequency adjustments to ticks")
Assisted-by Kiro:claude-opus-4.6-1m
---
 kernel/time/timekeeping.c | 6 ++++++
 1 file changed, 6 insertions(+)
kernel/time/timekeeping.c +6 -0
index b99171e71e0ac..4d8927aeca974 100644
@@ -2015,6 +2015,11 @@ static __always_inline void timekeeping_apply_adjustment(struct timekeeper *tk,
 	 *	xtime_nsec_2 = xtime_nsec_1 - offset
 	 * Which simplifies to:
 	 *	xtime_nsec -= offset
+	 *
+	 * When subtracting offset from xtime_nsec, the same amount
+	 * (in appropriate units) has to be added to ntp_error, in
+	 * order to correctly track the delta between the time
+	 * reported in xtime_nsec, and the intended time.
 	 */
 	if ((mult_adj > 0) && (tk->tkr_mono.mult + mult_adj < mult_adj)) {
 		/* NTP adjustment caused clocksource mult overflow */
@@ -2025,6 +2030,7 @@ static __always_inline void timekeeping_apply_adjustment(struct timekeeper *tk,
 	tk->tkr_mono.mult += mult_adj;
 	tk->xtime_interval += interval;
 	tk->tkr_mono.xtime_nsec -= offset;
+	tk->ntp_error += offset << tk->ntp_error_shift;
 }
 
 /*
Signature · 1 line
2.53.0
author maintainer
#455 lore raw

PATCH 441/1376 clk: qcom: gdsc: propagate gdsc_check_status() errors from gdsc_poll_status

In reply to Greg Kroah-Hartman

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

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

From: Herman van Hazendonk <[email protected]>

[ Upstream commit d69f0c2b8d292b4890c9f0fbe184dfc26c4de86c ]

gdsc_check_status() returns negative errno when the underlying regmap_read() fails -- e.g. when a parent regmap dies during system suspend, a CSR is removed by an HW debug tool, or the bus controller goes into protection. gdsc_poll_status() treats the result as a plain boolean ("is the GDSC in the requested state?"), so any negative error return is truncated to "true" and the poll exits with success even though the rail's real state is unknown:

	do {
		if (gdsc_check_status(sc, status))
			return 0;
	} while (ktime_us_delta(ktime_get(), start) < STATUS_POLL_TIMEOUT_US);

	if (gdsc_check_status(sc, status))
		return 0;

	return -ETIMEDOUT;

This silently misleads gdsc_toggle_logic() (which writes/un-writes SW_COLLAPSE on the strength of the poll succeeding) and the gdsc_init() sync path (which assumes the readback represents real silicon state).

Latch the return value, propagate negative errno immediately, and only treat a strictly-positive value as "reached the target state". Make the same change in the post-timeout final check so a regmap that comes back after the deadline does not silently degrade to -ETIMEDOUT.

Fixes 77b1067a19b4 ("clk: qcom: gdsc: Add support for gdscs with gds hw controller")
---
 drivers/clk/qcom/gdsc.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/clk/qcom/gdsc.c +9 -2
index 208fc430ec98f..c17aebb020706 100644
@@ -103,14 +103,21 @@ static int gdsc_hwctrl(struct gdsc *sc, bool en)
 static int gdsc_poll_status(struct gdsc *sc, enum gdsc_status status)
 {
 	ktime_t start;
+	int ret;
 
 	start = ktime_get();
 	do {
-		if (gdsc_check_status(sc, status))
+		ret = gdsc_check_status(sc, status);
+		if (ret < 0)
+			return ret;
+		if (ret)
 			return 0;
 	} while (ktime_us_delta(ktime_get(), start) < STATUS_POLL_TIMEOUT_US);
 
-	if (gdsc_check_status(sc, status))
+	ret = gdsc_check_status(sc, status);
+	if (ret < 0)
+		return ret;
+	if (ret)
 		return 0;
 
 	return -ETIMEDOUT;
Signature · 1 line
2.53.0
author maintainer
#456 lore raw

PATCH 442/1376 clk: qcom: gdsc: propagate gdsc_enable() failure for ALWAYS_ON domains

In reply to Greg Kroah-Hartman

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

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

From: Herman van Hazendonk <[email protected]>

[ Upstream commit eea55fc694e132aacbe2cf4be7f345115e3d1801 ]

GENPD_FLAG_ALWAYS_ON requires the underlying domain to be on at genpd_init() time -- the framework will refuse to register the domain otherwise. When the cold readback in gdsc_init() finds an ALWAYS_ON GDSC powered down, the driver tries to bring it back up:

	} else if (sc->flags & ALWAYS_ON) {
		/* If ALWAYS_ON GDSCs are not ON, turn them ON */
		gdsc_enable(&sc->pd);
		on = true;
	}

but discards the return value: if gdsc_enable() fails (regmap write error, the long-form sequence's status poll times out, or the HW_CTRL hand-off errors) the code still sets on=true and falls through to pm_genpd_init(..., !on) -- which then registers the domain in the ON state and sets GENPD_FLAG_ALWAYS_ON, even though the silicon is actually off. Subsequent consumer probes will see genpd report "on" while accessing dead registers and hang or read garbage.

Catch the failure and surface it: returning the error from gdsc_init() makes the provider probe fail with the underlying errno, which propagates to consumers as -EPROBE_DEFER (or fatal if the hardware really is broken) rather than silently lying about the rail state.

---
 drivers/clk/qcom/gdsc.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/clk/qcom/gdsc.c +3 -1
index c17aebb020706..119d96dfa853e 100644
@@ -481,7 +481,9 @@ static int gdsc_init(struct gdsc *sc)
 
 	} else if (sc->flags & ALWAYS_ON) {
 		/* If ALWAYS_ON GDSCs are not ON, turn them ON */
-		gdsc_enable(&sc->pd);
+		ret = gdsc_enable(&sc->pd);
+		if (ret)
+			return ret;
 		on = true;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#457 lore raw

PATCH 443/1376 clk: qcom: gdsc: tear down per-domain genpds in gdsc_unregister()

In reply to Greg Kroah-Hartman

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

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

From: Herman van Hazendonk <[email protected]>

[ Upstream commit 86b23609d5e17a770d03037e53c6a443e742a6e6 ]

gdsc_unregister() removes the OF provider entry and tears down the parent/subdomain wiring, but never calls pm_genpd_remove() on the individual generic_pm_domain structures registered by gdsc_init():

	void gdsc_unregister(struct gdsc_desc *desc)
	{
		struct device *dev = desc->dev;
		size_t num = desc->num;

		gdsc_pm_subdomain_remove(desc, num);
		of_genpd_del_provider(dev->of_node);
	}

That leaves dangling entries on the global gpd_list. After a provider unbind/rebind cycle (deferred-probe replay during early boot, real module unload of a clk driver that owns GDSCs, or an OF-overlay tear- down) the next gdsc_init() will end up trying to re-register a name that is still in the list and pm_genpd_init() returns -EEXIST.

While we are here, flip the order so the consumer-facing OF provider entry is the first thing removed -- otherwise a fresh of_genpd_get_from_provider() call racing with the teardown could attach to a domain that is mid-removal.

Iterate the scs[] array and pm_genpd_remove() each registered domain after the subdomain links are torn down. The regulators stay devm- managed (devm_regulator_get_optional() in gdsc_register()), so the release happens automatically when the underlying device is unbound; just the genpd accounting needs to be undone explicitly.

---
 drivers/clk/qcom/gdsc.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/clk/qcom/gdsc.c +9 -1
index 119d96dfa853e..83320559d2188 100644
@@ -600,10 +600,18 @@ int gdsc_register(struct gdsc_desc *desc,
 void gdsc_unregister(struct gdsc_desc *desc)
 {
 	struct device *dev = desc->dev;
+	struct gdsc **scs = desc->scs;
 	size_t num = desc->num;
+	int i;
 
-	gdsc_pm_subdomain_remove(desc, num);
 	of_genpd_del_provider(dev->of_node);
+	gdsc_pm_subdomain_remove(desc, num);
+
+	for (i = 0; i < num; i++) {
+		if (!scs[i])
+			continue;
+		pm_genpd_remove(&scs[i]->pd);
+	}
 }
 
 /*
Signature · 1 line
2.53.0
author maintainer
#458 lore raw

PATCH 444/1376 arm64: dts: qcom: sc8180x-primus: Rename regulator nodes

In reply to Greg Kroah-Hartman

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

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

From: Konrad Dybcio <[email protected]>

[ Upstream commit ae51d9396f9318189e91578878409d8ada152edb ]

The nodes would be sorted correctly, if their names started with "regulator-" (which is the style used in the latest submissions). Touch that up.

Stable-dep-of: 80bf2eb87bfb ("arm64: dts: qcom: sc8180x-primus: Describe the display power net")

---
 arch/arm64/boot/dts/qcom/sc8180x-primus.dts | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
arch/arm64/boot/dts/qcom/sc8180x-primus.dts +4 -4
index 79b4d293ea1e7..09dc42f5f2f86 100644
@@ -165,7 +165,7 @@ reserved-region@9a500000 {
 		};
 	};
 
-	vreg_nvme_0p9: nvme-0p9-regulator {
+	vreg_nvme_0p9: regulator-nvme-0p9 {
 		compatible = "regulator-fixed";
 		regulator-name = "vreg_nvme_0p9";
 
@@ -175,7 +175,7 @@ vreg_nvme_0p9: nvme-0p9-regulator {
 		regulator-always-on;
 	};
 
-	vreg_nvme_3p3: nvme-3p3-regulator {
+	vreg_nvme_3p3: regulator-nvme-3p3 {
 		compatible = "regulator-fixed";
 		regulator-name = "vreg_nvme_3p3";
 
@@ -188,7 +188,7 @@ vreg_nvme_3p3: nvme-3p3-regulator {
 		regulator-always-on;
 	};
 
-	vdd_kb_tp_3v3: vdd-kb-tp-3v3-regulator {
+	vdd_kb_tp_3v3: regulator-vdd-kb-tp-3v3 {
 		compatible = "regulator-fixed";
 		regulator-name = "vdd_kb_tp_3v3";
 		regulator-min-microvolt = <3300000>;
@@ -203,7 +203,7 @@ vdd_kb_tp_3v3: vdd-kb-tp-3v3-regulator {
 		pinctrl-0 = <&kb_tp_3v3_en_active_state>;
 	};
 
-	vph_pwr: vph-pwr-regulator {
+	vph_pwr: regulator-vph-pwr {
 		compatible = "regulator-fixed";
 		regulator-name = "vph_pwr";
 		regulator-min-microvolt = <3700000>;
Signature · 1 line
2.53.0
author maintainer
#459 lore raw

PATCH 445/1376 arm64: dts: qcom: sc8180x-primus: Describe the display power net

In reply to Greg Kroah-Hartman

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

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

From: Konrad Dybcio <[email protected]>

[ Upstream commit 80bf2eb87bfbf1b7bc7b12228cbcc710b0a26275 ]

Describe and wire up the power supplies for the eDP panel and its backlight. Previously, this was only working because of settings inherited from the bootloader.

---
 arch/arm64/boot/dts/qcom/sc8180x-primus.dts | 48 ++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)
arch/arm64/boot/dts/qcom/sc8180x-primus.dts +47 -1
index 09dc42f5f2f86..4d1d079a1f37e 100644
@@ -27,9 +27,10 @@ backlight: backlight {
 		compatible = "pwm-backlight";
 		pwms = <&pmc8180c_lpg 4 1000000>;
 		enable-gpios = <&pmc8180c_gpios 8 GPIO_ACTIVE_HIGH>;
+		power-supply = <&vled_bl_pw>;
 
-		pinctrl-names = "default";
 		pinctrl-0 = <&bl_pwm_default>;
+		pinctrl-names = "default";
 	};
 
 	chosen {
@@ -165,6 +166,38 @@ reserved-region@9a500000 {
 		};
 	};
 
+	vled_bl_pw: regulator-vled-bl-pw {
+		compatible = "regulator-fixed";
+
+		regulator-name = "VLED_BL_PW";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+
+		gpio = <&pmc8180_2_gpios 1 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+
+		pinctrl-0 = <&bl_pwr_en>;
+		pinctrl-names = "default";
+
+		regulator-boot-on;
+	};
+
+	vreg_lcm_3v3: regulator-edp-3p3 {
+		compatible = "regulator-fixed";
+
+		regulator-name = "VREG_LCM_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+
+		gpio = <&tlmm 130 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+
+		pinctrl-0 = <&lcm_3v3_en>;
+		pinctrl-names = "default";
+
+		regulator-boot-on;
+	};
+
 	vreg_nvme_0p9: regulator-nvme-0p9 {
 		compatible = "regulator-fixed";
 		regulator-name = "vreg_nvme_0p9";
@@ -541,6 +574,7 @@ &mdss_edp {
 	aux-bus {
 		panel {
 			compatible = "edp-panel";
+			power-supply = <&vreg_lcm_3v3>;
 
 			backlight = <&backlight>;
 
@@ -778,6 +812,12 @@ &xo_board_clk {
 };
 
 /* PINCTRL */
+&pmc8180_2_gpios {
+	bl_pwr_en: bl-pwr-en-state {
+		pins = "gpio1";
+		function = "normal";
+	};
+};
 
 &pmc8180c_gpios {
 	bl_pwm_default: bl-pwm-default-state {
@@ -959,4 +999,10 @@ rx-pins {
 			bias-pull-up;
 		};
 	};
+
+	lcm_3v3_en: lcm-3v3-en-state {
+		pins = "gpio130";
+		function = "gpio";
+		bias-disable;
+	};
 };
Signature · 1 line
2.53.0
author maintainer
#460 lore raw

PATCH 446/1376 arm64: dts: qcom: sc8180x-lenovo-flex-5g: Rename regulator nodes

In reply to Greg Kroah-Hartman

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

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

From: Konrad Dybcio <[email protected]>

[ Upstream commit 0b1c6d2a65fc41aa0d5f6617dd04043384678d61 ]

Align with the contemporary way of naming regulator nodes (regulator- prefix) in preparation for adding more of them.

Reorder the renamed entries to match the expectations of the DT coding style doc.

Stable-dep-of: d5f5c089858f ("arm64: dts: qcom: sc8180x-lenovo-flex-5g: Describe the display power net")

---
 .../boot/dts/qcom/sc8180x-lenovo-flex-5g.dts     | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts +8 -8
index 62de4774c556d..357b1214c1738 100644
@@ -162,14 +162,7 @@ cdsp_mem: cdsp-region@98900000 {
 		};
 	};
 
-	vph_pwr: vph-pwr-regulator {
-		compatible = "regulator-fixed";
-		regulator-name = "vph_pwr";
-		regulator-min-microvolt = <3700000>;
-		regulator-max-microvolt = <3700000>;
-	};
-
-	vreg_s4a_1p8: pm8150-s4-regulator {
+	vreg_s4a_1p8: regulator-pm8150-s4 {
 		compatible = "regulator-fixed";
 		regulator-name = "vreg_s4a_1p8";
 
@@ -182,6 +175,13 @@ vreg_s4a_1p8: pm8150-s4-regulator {
 		vin-supply = <&vph_pwr>;
 	};
 
+	vph_pwr: regulator-vph-pwr {
+		compatible = "regulator-fixed";
+		regulator-name = "vph_pwr";
+		regulator-min-microvolt = <3700000>;
+		regulator-max-microvolt = <3700000>;
+	};
+
 	usbprim-sbu-mux {
 		compatible = "pericom,pi3usb102", "gpio-sbu-mux";
 
Signature · 1 line
2.53.0
author maintainer
#461 lore raw

PATCH 447/1376 arm64: dts: qcom: sc8180x-lenovo-flex-5g: Describe the display power net

In reply to Greg Kroah-Hartman

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

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

From: Konrad Dybcio <[email protected]>

[ Upstream commit d5f5c089858f7accd1e4574c0c09d811e90eb51f ]

Describe and wire up the power supplies for the eDP panel and its backlight. Previously, this was only working because of settings inherited from the bootloader.

---
 .../boot/dts/qcom/sc8180x-lenovo-flex-5g.dts  | 47 +++++++++++++++++++
 1 file changed, 47 insertions(+)
arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts +47 -0
index 357b1214c1738..debe9fa74724a 100644
@@ -26,6 +26,7 @@ backlight: backlight {
 		compatible = "pwm-backlight";
 		pwms = <&pmc8180c_lpg 4 1000000>;
 		enable-gpios = <&pmc8180c_gpios 8 GPIO_ACTIVE_HIGH>;
+		power-supply = <&vled_bl_pw>;
 
 		pinctrl-0 = <&bl_pwm_default>;
 		pinctrl-names = "default";
@@ -162,6 +163,38 @@ cdsp_mem: cdsp-region@98900000 {
 		};
 	};
 
+	vled_bl_pw: regulator-vled-bl-pw {
+		compatible = "regulator-fixed";
+
+		regulator-name = "VLED_BL_PW";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+
+		gpio = <&pmc8180_2_gpios 1 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+
+		pinctrl-0 = <&bl_pwr_en>;
+		pinctrl-names = "default";
+
+		regulator-boot-on;
+	};
+
+	vreg_lcm_3v3: regulator-edp-3p3 {
+		compatible = "regulator-fixed";
+
+		regulator-name = "VREG_LCM_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+
+		gpio = <&tlmm 130 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+
+		pinctrl-0 = <&lcm_3v3_en>;
+		pinctrl-names = "default";
+
+		regulator-boot-on;
+	};
+
 	vreg_s4a_1p8: regulator-pm8150-s4 {
 		compatible = "regulator-fixed";
 		regulator-name = "vreg_s4a_1p8";
@@ -446,6 +479,7 @@ &mdss_edp {
 	aux-bus {
 		panel {
 			compatible = "edp-panel";
+			power-supply = <&vreg_lcm_3v3>;
 			no-hpd;
 
 			backlight = <&backlight>;
@@ -484,6 +518,13 @@ &pcie3_phy {
 	status = "okay";
 };
 
+&pmc8180_2_gpios {
+	bl_pwr_en: bl-pwr-en-state {
+		pins = "gpio1";
+		function = "normal";
+	};
+};
+
 &pmc8180_pwrkey {
 	status = "okay";
 };
@@ -781,6 +822,12 @@ ts_int_default: ts-int-default-state {
 		drive-strength = <2>;
 	};
 
+	lcm_3v3_en: lcm-3v3-en-state {
+		pins = "gpio130";
+		function = "gpio";
+		bias-disable;
+	};
+
 	usbprim_sbu_default: usbprim-sbu-state {
 		oe-n-pins {
 			pins = "gpio152";
Signature · 1 line
2.53.0
author maintainer
#462 lore raw

PATCH 448/1376 perf data convert json: Fix trace_seq memory leak in process_sample_event()

In reply to Greg Kroah-Hartman

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

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

From: Tanushree Shah <[email protected]>

[ Upstream commit dcb87c88952046ef43cb5ba3a5b95eb29c362a16 ]

Unlike the in-kernel trace_seq which uses a statically allocated buffer, the userspace traceevent library's trace_seq uses a dynamically allocated one. Therefore, every trace_seq_init() call must be paired with a trace_seq_destroy(), otherwise it produces a memory leak.

In process_sample_event(), a trace_seq is initialized for each field when formatting tracepoint raw_data, but the matching trace_seq_destroy() is never called, leaking memory for every field of every sample processed.

Add the missing trace_seq_destroy() after using the trace_seq buffer to properly free the allocated memory.

Detected with Valgrind on a perf.data file with 2,729 tracepoint samples:
Before: definitely lost: 55,537,664 bytes in 13,559 blocks
After: definitely lost: 0 bytes in 0 blocks

Fixes 9d895e468429 ("perf data: Add tracepoint fields when converting to JSON")
---
 tools/perf/util/data-convert-json.c | 1 +
 1 file changed, 1 insertion(+)
tools/perf/util/data-convert-json.c +1 -0
index 20bfb0884e9ea..395b231cf16c4 100644
@@ -242,6 +242,7 @@ static int process_sample_event(const struct perf_tool *tool,
 				trace_seq_init(&s);
 				tep_print_field(&s, sample->raw_data, fields[i]);
 				output_json_key_string(out, true, 3, fields[i]->name, s.buffer);
+				trace_seq_destroy(&s);
 
 				i++;
 			}
Signature · 1 line
2.53.0
author maintainer
#463 lore raw

PATCH 449/1376 thermal/drivers/rcar: Fix error checking in probe()

In reply to Greg Kroah-Hartman

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

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

From: Dan Carpenter <[email protected]>

[ Upstream commit dd04ad1cdabcad51e34b74b4e91b9aeb7180d05d ]

This code accidentally calls thermal_zone_device_enable() before checking whether thermal_zone_device_register_with_trips() failed. Move the call until later to avoid an error pointer dereference of "priv->zone".

The driver works differently depending on if we are using OF thermal or not. We use thermal_add_hwmon_sysfs() if we are using OF thermal and call thermal_zone_device_enable() if not. We can share same error check for if either of these fail.

Moving the thermal_zone_device_enable() call is a bit cleaner as well. The original code used a three step process to cleanup:
1. Call thermal_zone_device_unregister() to cleanup.
2. Set priv->zone to an error pointer to preserve the error code.
3. Set priv->zone to NULL to avoid a second call to thermal_zone_device_unregister() in the rcar_thermal_remove() function.

Now we can just do a direct goto error_unregister and rcar_thermal_remove() handles the cleanup properly.

Fixes bbcf90c0646a ("thermal: Explicitly enable non-changing thermal zone devices")
---
 drivers/thermal/renesas/rcar_thermal.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)
drivers/thermal/renesas/rcar_thermal.c +5 -10
index ddc8341e5c3fa..00517681a8bb1 100644
@@ -492,12 +492,6 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 				"rcar_thermal", trips, ARRAY_SIZE(trips), priv,
 						&rcar_thermal_zone_ops, NULL, 0,
 						idle);
-
-			ret = thermal_zone_device_enable(priv->zone);
-			if (ret) {
-				thermal_zone_device_unregister(priv->zone);
-				priv->zone = ERR_PTR(ret);
-			}
 		}
 		if (IS_ERR(priv->zone)) {
 			dev_err(dev, "can't register thermal zone\n");
@@ -506,11 +500,12 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 			goto error_unregister;
 		}
 
-		if (chip->use_of_thermal) {
+		if (chip->use_of_thermal)
 			ret = thermal_add_hwmon_sysfs(priv->zone);
-			if (ret)
-				goto error_unregister;
-		}
+		else
+			ret = thermal_zone_device_enable(priv->zone);
+		if (ret)
+			goto error_unregister;
 
 		rcar_thermal_irq_enable(priv);
 
Signature · 1 line
2.53.0
author maintainer
#464 lore raw

PATCH 450/1376 usb: typec: ucsi: unregister debugfs entries on teardown

In reply to Greg Kroah-Hartman

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

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

From: Bjorn Andersson <[email protected]>

[ Upstream commit eed73a65ab609b79d53de88cccc34b36dfe753c4 ]

ucsi_register() creates per-instance debugfs entries, but ucsi_unregister() keeps them around until ucsi_destroy().

Drivers like ucsi_glink that unregister/register the same UCSI instance across remoteproc restart then try to create an already existing debugfs directory and log:

debugfs: 'pmic_glink.ucsi.0' already exists in 'ucsi'

Unregister debugfs entries as part of ucsi_unregister(), and clear ucsi->debugfs after freeing it so repeated unregister paths remain safe.

---
 drivers/usb/typec/ucsi/debugfs.c | 1 +
 drivers/usb/typec/ucsi/ucsi.c    | 2 ++
 2 files changed, 3 insertions(+)
drivers/usb/typec/ucsi/debugfs.c +1 -0
index f67733cecfdf5..2f5a3ae1fd852 100644
@@ -89,6 +89,7 @@ void ucsi_debugfs_unregister(struct ucsi *ucsi)
 
 	debugfs_remove_recursive(ucsi->debugfs->dentry);
 	kfree(ucsi->debugfs);
+	ucsi->debugfs = NULL;
 }
 
 void ucsi_debugfs_init(void)
drivers/usb/typec/ucsi/ucsi.c +2 -0
index 5e7226aed7005..b80f68e34d21d 100644
@@ -2102,6 +2102,8 @@ void ucsi_unregister(struct ucsi *ucsi)
 	cancel_delayed_work_sync(&ucsi->work);
 	cancel_work_sync(&ucsi->resume_work);
 
+	ucsi_debugfs_unregister(ucsi);
+
 	/* Disable notifications */
 	ucsi->ops->async_control(ucsi, cmd);
 
Signature · 1 line
2.53.0
author maintainer
#465 lore raw

PATCH 451/1376 usb: gadget: r8a66597: avoid double free of ep0_req in probe error path

In reply to Greg Kroah-Hartman

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

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

From: Hongyan Xu <[email protected]>

[ Upstream commit 41d541e3718db01668a4cd29815ee4b3b55f76d2 ]

If usb_add_gadget_udc() fails, r8a66597_probe() jumps to err_add_udc and frees ep0_req, then falls through to clean_up2 where ep0_req is freed again when it is non-NULL.

Remove the redundant free from err_add_udc and keep the cleanup in clean_up2 so the request is released exactly once.

Fixes 776976a67ae2 ("usb: gadget: r8a66597-udc: cleanup error path")

Issue found using a prototype static analysis tool and confirmed by code review.

---
 drivers/usb/gadget/udc/r8a66597-udc.c | 1 -
 1 file changed, 1 deletion(-)
drivers/usb/gadget/udc/r8a66597-udc.c +0 -1
index db4a10a979f9d..813b1e1af4350 100644
@@ -1951,7 +1951,6 @@ static int r8a66597_probe(struct platform_device *pdev)
 	return 0;
 
 err_add_udc:
-	r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req);
 clean_up2:
 	if (r8a66597->pdata->on_chip)
 		clk_disable_unprepare(r8a66597->clk);
Signature · 1 line
2.53.0
author maintainer
#466 lore raw

PATCH 452/1376 udf: Mark LVID buffer as uptodate before marking it dirty

In reply to Greg Kroah-Hartman

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

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

From: Aleksandr Nogikh <[email protected]>

[ Upstream commit fb0601134c7e51728bd098abc6909315de1e5d86 ]

When an I/O error occurs while writing the Logical Volume Integrity Descriptor (LVID) buffer to the block device, the block layer's completion handler (end_buffer_write_sync()) clears the BH_Uptodate flag on the buffer. However, the buffer still contains valid LVID data in memory. If the filesystem is subsequently remounted read-write or synced, udf_open_lvid() or udf_sync_fs() will modify the LVID buffer and call mark_buffer_dirty(). This triggers a spurious WARN_ON_ONCE(!buffer_uptodate(bh)) warning in mark_buffer_dirty() because the buffer is not marked uptodate, even though its in-memory contents are valid and are about to be overwritten.

To prevent this spurious warning, unconditionally set the BH_Uptodate flag before calling mark_buffer_dirty() in udf_open_lvid() and udf_sync_fs(). This acknowledges that the in-memory buffer is valid and matches the workaround previously applied to udf_close_lvid() in commit 853a0c25baf9 ("udf: Mark LVID buffer as uptodate before marking it dirty"). Extending this workaround ensures consistent behavior across all LVID updates.

Buffer I/O error on dev loop0, logical block 128, lost sync page write

------------[ cut here ]------------
!buffer_uptodate(bh)
WARNING: fs/buffer.c:1087 at mark_buffer_dirty+0x299/0x410 fs/buffer.c:1087
...
Call Trace:
 <TASK>
 udf_open_lvid+0x369/0x5b0 fs/udf/super.c:2078
 udf_reconfigure+0x336/0x540 fs/udf/super.c:679
 reconfigure_super+0x232/0x8f0 fs/super.c:1080
 vfs_cmd_reconfigure fs/fsopen.c:268 [inline]
 vfs_fsconfig_locked+0x171/0x320 fs/fsopen.c:297
 __do_sys_fsconfig fs/fsopen.c:463 [inline]
 __se_sys_fsconfig+0x6b9/0x810 fs/fsopen.c:350
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 </TASK>
Fixes 853a0c25baf9 ("udf: Mark LVID buffer as uptodate before marking it dirty")
Assisted-by Gemini:gemini-3.1-pro-preview Gemini:gemini-3-flash-preview syzbot
Reported-by [email protected]
---
 fs/udf/super.c | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)
fs/udf/super.c +14 -9
index c7c5fd45166b9..f91b231b7d7bd 100644
@@ -2050,6 +2050,17 @@ static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt,
 	return 0;
 }
 
+static void udf_mark_buffer_dirty(struct buffer_head *bh)
+{
+	/*
+	 * We set buffer uptodate unconditionally here to avoid spurious
+	 * warnings from mark_buffer_dirty() when previous EIO has marked
+	 * the buffer as !uptodate
+	 */
+	set_buffer_uptodate(bh);
+	mark_buffer_dirty(bh);
+}
+
 static void udf_finalize_lvid(struct logicalVolIntegrityDesc *lvid)
 {
 	struct timespec64 ts;
@@ -2085,7 +2096,7 @@ static void udf_open_lvid(struct super_block *sb)
 		UDF_SET_FLAG(sb, UDF_FLAG_INCONSISTENT);
 
 	udf_finalize_lvid(lvid);
-	mark_buffer_dirty(bh);
+	udf_mark_buffer_dirty(bh);
 	sbi->s_lvid_dirty = 0;
 	mutex_unlock(&sbi->s_alloc_mutex);
 	/* Make opening of filesystem visible on the media immediately */
@@ -2118,14 +2129,8 @@ static void udf_close_lvid(struct super_block *sb)
 	if (!UDF_QUERY_FLAG(sb, UDF_FLAG_INCONSISTENT))
 		lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE);
 
-	/*
-	 * We set buffer uptodate unconditionally here to avoid spurious
-	 * warnings from mark_buffer_dirty() when previous EIO has marked
-	 * the buffer as !uptodate
-	 */
-	set_buffer_uptodate(bh);
 	udf_finalize_lvid(lvid);
-	mark_buffer_dirty(bh);
+	udf_mark_buffer_dirty(bh);
 	sbi->s_lvid_dirty = 0;
 	mutex_unlock(&sbi->s_alloc_mutex);
 	/* Make closing of filesystem visible on the media immediately */
@@ -2407,7 +2412,7 @@ static int udf_sync_fs(struct super_block *sb, int wait)
 		 * Blockdevice will be synced later so we don't have to submit
 		 * the buffer for IO
 		 */
-		mark_buffer_dirty(bh);
+		udf_mark_buffer_dirty(bh);
 		sbi->s_lvid_dirty = 0;
 	}
 	mutex_unlock(&sbi->s_alloc_mutex);
Signature · 1 line
2.53.0
author maintainer
#467 lore raw

PATCH 453/1376 perf vendor events amd: Reintroduce deprecated Zen 5 core events

In reply to Greg Kroah-Hartman

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

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

From: Sandipan Das <[email protected]>

[ Upstream commit eda39f98bbc5ce8b7b0be10193d2de38ed59da6c ]

Maintain backward compatibility by reintroducing the events that were previously removed by commit 047979af3bf6 ("perf vendor events amd:
Update Zen 5 core events"). Also set the deprecated flag and update the descriptions to point users to the correct alternative.

---
 .../arch/x86/amdzen5/floating-point.json      | 42 +++++++++++++++++++
 1 file changed, 42 insertions(+)
tools/perf/pmu-events/arch/x86/amdzen5/floating-point.json +42 -0
index 569975b53cc33..50d38434f8d3d 100644
@@ -383,6 +383,13 @@
     "BriefDescription": "Retired MMX integer VNNI ops.",
     "UMask": "0x0c"
   },
+  {
+    "EventName": "sse_avx_ops_retired.mmx_pack",
+    "EventCode": "0x0b",
+    "BriefDescription": "This event is deprecated. Refer to new event sse_avx_ops_retired.mmx_vnni",
+    "Deprecated": "1",
+    "UMask": "0x0c"
+  },
   {
     "EventName": "sse_avx_ops_retired.mmx_logical",
     "EventCode": "0x0b",
@@ -449,6 +456,13 @@
     "BriefDescription": "Retired SSE and AVX integer convert or pack ops.",
     "UMask": "0x80"
   },
+  {
+    "EventName": "sse_avx_ops_retired.sse_avx_clm",
+    "EventCode": "0x0b",
+    "BriefDescription": "This event is deprecated. Refer to new event sse_avx_ops_retired.sse_avx_cvt",
+    "Deprecated": "1",
+    "UMask": "0x80"
+  },
   {
     "EventName": "sse_avx_ops_retired.sse_avx_shift",
     "EventCode": "0x0b",
@@ -473,6 +487,13 @@
     "BriefDescription": "Retired SSE and AVX integer VNNI ops.",
     "UMask": "0xc0"
   },
+  {
+    "EventName": "sse_avx_ops_retired.sse_avx_pack",
+    "EventCode": "0x0b",
+    "BriefDescription": "This event is deprecated. Refer to new event sse_avx_ops_retired.sse_avx_vnni",
+    "Deprecated": "1",
+    "UMask": "0xc0"
+  },
   {
     "EventName": "sse_avx_ops_retired.sse_avx_logical",
     "EventCode": "0x0b",
@@ -731,6 +752,13 @@
     "BriefDescription": "Retired 128-bit packed integer convert or pack ops.",
     "UMask": "0x08"
   },
+  {
+    "EventName": "packed_int_op_type.int128_clm",
+    "EventCode": "0x0d",
+    "BriefDescription": "This event is deprecated. Refer to new event packed_int_op_type.int128_cvt",
+    "Deprecated": "1",
+    "UMask": "0x08"
+  },
   {
     "EventName": "packed_int_op_type.int128_shift",
     "EventCode": "0x0d",
@@ -755,6 +783,13 @@
     "BriefDescription": "Retired 128-bit packed integer VNNI ops.",
     "UMask": "0x0c"
   },
+  {
+    "EventName": "packed_int_op_type.int128_pack",
+    "EventCode": "0x0d",
+    "BriefDescription": "This event is deprecated. Refer to new event packed_int_op_type.int128_vnni",
+    "Deprecated": "1",
+    "UMask": "0x0c"
+  },
   {
     "EventName": "packed_int_op_type.int128_logical",
     "EventCode": "0x0d",
@@ -845,6 +880,13 @@
     "BriefDescription": "Retired 256-bit packed integer VNNI ops.",
     "UMask": "0xc0"
   },
+  {
+    "EventName": "packed_int_op_type.int256_pack",
+    "EventCode": "0x0d",
+    "BriefDescription": "This event is deprecated. Refer to new event packed_int_op_type.int256_vnni",
+    "Deprecated": "1",
+    "UMask": "0xc0"
+  },
   {
     "EventName": "packed_int_op_type.int256_logical",
     "EventCode": "0x0d",
Signature · 1 line
2.53.0
author maintainer
#468 lore raw

PATCH 454/1376 perf dso: Fix kallsyms DSO detection with fallback logic

In reply to Greg Kroah-Hartman

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

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

From: Tanushree Shah <[email protected]>

[ Upstream commit 8c5f60344b07f839267c0c835962e2206143be85 ]

The current kallsyms detection in dso__is_kallsyms() uses the dso_binary_type enum which fixes the issue of kallsyms being cached in the build-id cache for out-of-tree modules.

However, during build-id injection in perf record/inject, dso_binary_type has not been explicitly set yet,so dso__binary_type() returns DSO_BINARY_TYPE__NOT_FOUND instead of DSO_BINARY_TYPE__KALLSYMS for the kernel DSO. The current check then fails to identify it as kallsyms, causing build-id symlinks to not be created in ~/.debug/.build-id/ and perf archive to fail with "Cannot stat" errors.

Steps to reproduce the issue:
1. rm -rf ~/.debug/.build-id
2. perf record sleep 1
3. perf archive

Fix by falling back to matching long_name against the known kallsyms strings explicitly when binary_type is not yet set
(== DSO_BINARY_TYPE__NOT_FOUND). Use strcmp() for exact matching of fixed names and strict validation for guest kallsyms with embedded PID to prevent path traversal attacks.

Fixes ebf0b332732d ("perf dso: fix dso__is_kallsyms() check")
---
 tools/perf/util/dso.h | 57 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 56 insertions(+), 1 deletion(-)
tools/perf/util/dso.h +56 -1
index c0472a41147c3..bb0238acd583d 100644
@@ -9,6 +9,7 @@
 #include <stdbool.h>
 #include <stdio.h>
 #include <linux/bitops.h>
+#include <string.h>
 #include "build-id.h"
 #include "mutex.h"
 #include <internal/rc_check.h>
@@ -19,6 +20,40 @@ struct perf_env;
 
 #define DSO__NAME_KALLSYMS	"[kernel.kallsyms]"
 #define DSO__NAME_KCORE		"[kernel.kcore]"
+#define DSO__NAME_GUEST_KALLSYMS		"[guest.kernel.kallsyms]"
+#define DSO__NAME_GUEST_KALLSYMS_PID_PREFIX	"[guest.kernel.kallsyms."
+
+/*
+ * Validate names of the form "[guest.kernel.kallsyms.<pid>]", where
+ * <pid> is the PID of the guest VM and varies per guest, so it
+ * cannot be matched with strcmp() against a fixed string.
+ *
+ * Every character after the fixed prefix must be a decimal digit,
+ * with ']' immediately terminating the digit run and nothing
+ * following it. This rules out '/', "..", or any other character
+ * being smuggled into the name.
+ */
+static inline bool is_guest_kallsyms_pid_name(const char *name)
+{
+	const size_t prefix_len = sizeof(DSO__NAME_GUEST_KALLSYMS_PID_PREFIX) - 1;
+	size_t digits;
+
+	if (strncmp(name, DSO__NAME_GUEST_KALLSYMS_PID_PREFIX, prefix_len) != 0)
+		return false;
+
+	digits = strspn(name + prefix_len, "0123456789");
+	if (digits == 0)
+		return false;
+
+	/* ']' must terminate the digit run, with nothing trailing it */
+	if (name[prefix_len + digits] != ']')
+		return false;
+
+	if (name[prefix_len + digits + 1] != '\0')
+		return false;
+
+	return true;
+}
 
 enum dso_binary_type {
 	DSO_BINARY_TYPE__KALLSYMS = 0,
@@ -809,8 +844,28 @@ static inline bool dso__is_kcore(const struct dso *dso)
 static inline bool dso__is_kallsyms(const struct dso *dso)
 {
 	enum dso_binary_type bt = dso__binary_type(dso);
+	const char *name;
+
+	if (bt == DSO_BINARY_TYPE__KALLSYMS || bt == DSO_BINARY_TYPE__GUEST_KALLSYMS)
+		return true;
+
+	if (bt != DSO_BINARY_TYPE__NOT_FOUND)
+		return false;
+
+	if (!dso__kernel(dso))
+		return false;
+
+	name = dso__long_name(dso);
+	if (!name)
+		return false;
+
+	if (!strcmp(name, DSO__NAME_KALLSYMS))
+		return true;
+
+	if (!strcmp(name, DSO__NAME_GUEST_KALLSYMS))
+		return true;
 
-	return bt == DSO_BINARY_TYPE__KALLSYMS || bt == DSO_BINARY_TYPE__GUEST_KALLSYMS;
+	return is_guest_kallsyms_pid_name(name);
 }
 
 bool dso__is_object_file(const struct dso *dso);
Signature · 1 line
2.53.0
author maintainer
#469 lore raw

PATCH 455/1376 bpf: Fix vmlinux BTF prep race in bpf_get_btf_vmlinux

In reply to Greg Kroah-Hartman

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

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

From: Daniel Borkmann <[email protected]>

[ Upstream commit 92863e678070f57c17c868e4bfa2441a5c61ad2b ]

bpf_get_btf_vmlinux() lazily parses the vmlinux BTF under the bpf_verifier_lock, but publishes the result through a plain store and re-checks it through a plain lockless load. Nothing orders the stores initializing the struct btf inside btf_parse_vmlinux() against the store publishing the pointer: On a weakly ordered arch, a concurrent first-time caller taking the lockless fast path could in principle observe the pointer before the parsed contents are visible. The mutex_unlock() does not help such a reader given it only synchronizes with a later acquisition of the same lock. Thus, publish the pointer with smp_store_release() and read it on the fast path with smp_load_acquire().

Acquire semantics are needed rather than a dependency-ordered READ_ONCE(): btf_parse_vmlinux() also populates globals outside the returned object (e.g. bpf_ctx_convert.t). An address dependency would only order accesses performed through the pointer and not cover other globals.

---
 kernel/bpf/verifier.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)
kernel/bpf/verifier.c +16 -4
index 99b3f539e431f..f9f2095eab4a0 100644
@@ -22781,13 +22781,25 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
 
 struct btf *bpf_get_btf_vmlinux(void)
 {
-	if (!btf_vmlinux && IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) {
+	/* Pairs with the smp_store_release() on the parse path below. */
+	struct btf *btf = smp_load_acquire(&btf_vmlinux);
+
+	if (!btf && IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) {
 		mutex_lock(&bpf_verifier_lock);
-		if (!btf_vmlinux)
-			btf_vmlinux = btf_parse_vmlinux();
+		btf = btf_vmlinux;
+		if (!btf) {
+			btf = btf_parse_vmlinux();
+			/*
+			 * Order the parsed BTF contents and the globals the
+			 * parse populated (e.g. bpf_ctx_convert.t) before
+			 * the pointer publication. Pairs with the acquire
+			 * on the lockless fast path above.
+			 */
+			smp_store_release(&btf_vmlinux, btf);
+		}
 		mutex_unlock(&bpf_verifier_lock);
 	}
-	return btf_vmlinux;
+	return btf;
 }
 
 int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u32 uattr_size)
Signature · 1 line
2.53.0
author maintainer
#470 lore raw

PATCH 456/1376 efi: fix stale reference to efi_recover_from_page_fault()

In reply to Greg Kroah-Hartman

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

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

From: Breno Leitao <[email protected]>

[ Upstream commit 718ee46ba4d95d28d50d3f6437afbbe2be531175 ]

efi_recover_from_page_fault() was renamed to efi_crash_gracefully_on_page_fault(), but the comment above enum efi_rts_ids was not updated. Use the current name.

Fixes c46f52231e79 ("x86/{fault,efi}: Fix and rename efi_recover_from_page_fault()")
---
 include/linux/efi.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
include/linux/efi.h +2 -2
index 2f1bfd7562eb2..06e8d3c69f9e6 100644
@@ -1239,8 +1239,8 @@ efi_call_acpi_prm_handler(efi_status_t (__efiapi *handler_addr)(u64, void *),
 
 /*
  * efi_runtime_service() function identifiers.
- * "NONE" is used by efi_recover_from_page_fault() to check if the page
- * fault happened while executing an efi runtime service.
+ * "NONE" is used by efi_crash_gracefully_on_page_fault() to check if the
+ * page fault happened while executing an efi runtime service.
  */
 enum efi_rts_ids {
 	EFI_NONE,
Signature · 1 line
2.53.0
author maintainer
#471 lore raw

PATCH 457/1376 bpf: Fix use-after-free on mm_struct in bpf_find_vma()

In reply to Greg Kroah-Hartman

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

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

From: Sanghyun Park <[email protected]>

[ Upstream commit 47b079e2117a2ee52e21f8b72935900c702fc0b5 ]

bpf_find_vma() reads task->mm and calls mmap_read_trylock(mm) without holding a reference on the mm. On a foreign task, a concurrent exit_mm() can free the mm_struct between the lockless read and the trylock, resulting in a use-after-free. mm_struct is not SLAB_TYPESAFE_BY_RCU.

For the current task, task->mm is stable. For a foreign task, pin the mm under task->alloc_lock and release it with mmput_async(), mirroring commit d8e27d2d22b6 ("bpf: fix mm lifecycle in open-coded task_vma iterator"). Use spin_trylock() instead of get_task_mm() so BPF context does not block on alloc_lock. Reject irqs-disabled contexts and !CONFIG_MMU on the foreign-task path because dropping the mm reference is not safe there.

Race:

CPU0 (BPF program) CPU1 (exiting task)
============================ ==========================
bpf_find_vma(foreign_task):

    mm = task->mm
                                      exit_mm():
                                        task->mm = NULL
                                        mmput(mm) -> frees mm_struct
    mmap_read_trylock(mm)
        // UAF on mm
---
 kernel/bpf/task_iter.c | 36 +++++++++++++++++++++++++++++++++---
 1 file changed, 33 insertions(+), 3 deletions(-)
kernel/bpf/task_iter.c +33 -3
index fc5f463ca529a..f3a7a96a77d7d 100644
@@ -760,6 +760,7 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
 	struct mmap_unlock_irq_work *work = NULL;
 	struct vm_area_struct *vma;
 	bool irq_work_busy = false;
+	bool __maybe_unused mmput_needed = false;
 	struct mm_struct *mm;
 	int ret = -ENOENT;
 
@@ -769,14 +770,38 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
 	if (!task)
 		return -ENOENT;
 
-	mm = task->mm;
+	if (task == current) {
+		mm = task->mm;
+	} else {
+		/*
+		 * Foreign task: pin task->mm against a concurrent exit_mm().
+		 * Use trylock on alloc_lock instead of get_task_mm()'s
+		 * blocking task_lock() to avoid deadlocking the target task.
+		 */
+		if (!IS_ENABLED(CONFIG_MMU))
+			return -EOPNOTSUPP;
+		if (irqs_disabled())
+			return -EBUSY;
+		if (!spin_trylock(&task->alloc_lock))
+			return -EBUSY;
+		mm = task->mm;
+		if (mm && !(task->flags & PF_KTHREAD)) {
+			mmget(mm);
+			mmput_needed = true;
+		} else {
+			mm = NULL;
+		}
+		spin_unlock(&task->alloc_lock);
+	}
 	if (!mm)
 		return -ENOENT;
 
 	irq_work_busy = bpf_mmap_unlock_get_irq_work(&work);
 
-	if (irq_work_busy || !mmap_read_trylock(mm))
-		return -EBUSY;
+	if (irq_work_busy || !mmap_read_trylock(mm)) {
+		ret = -EBUSY;
+		goto out;
+	}
 
 	vma = find_vma(mm, start);
 
@@ -786,6 +811,11 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
 		ret = 0;
 	}
 	bpf_mmap_unlock_mm(work, mm);
+out:
+#ifdef CONFIG_MMU
+	if (mmput_needed)
+		mmput_async(mm);
+#endif
 	return ret;
 }
 
Signature · 1 line
2.53.0
author maintainer
#472 lore raw

PATCH 458/1376 bus: mhi: ep: Fix device refcount leak in the error path of MHI device creation

In reply to Greg Kroah-Hartman

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

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

From: Yuho Choi <[email protected]>

[ Upstream commit 6f12862600bb70e599a614d706a095ea5f8f9858 ]

mhi_ep_create_device() takes one device reference for the UL channel and another for the DL channel after allocating the transfer device. These references are normally released by mhi_ep_destroy_device() before the device itself is removed.

If dev_set_name() or device_add() fails, the error path currently drops only one reference. The remaining channel references keep the device from being released and leave the channels associated with a device that was never registered.

Route both failures through a common unwind path that drops the DL channel reference, the UL channel reference, and the initial reference from device_initialize().

Fixes 297c77a0f273 ("bus: mhi: ep: Add support for creating and destroying MHI EP devices")
---
 drivers/bus/mhi/ep/main.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)
drivers/bus/mhi/ep/main.c +10 -5
index 2f58ad0f14b65..fd1d7c84fb1c5 100644
@@ -1340,14 +1340,19 @@ static int mhi_ep_create_device(struct mhi_ep_cntrl *mhi_cntrl, u32 ch_id)
 	ret = dev_set_name(&mhi_dev->dev, "%s_%s",
 		     dev_name(&mhi_cntrl->mhi_dev->dev),
 		     mhi_dev->name);
-	if (ret) {
-		put_device(&mhi_dev->dev);
-		return ret;
-	}
+	if (ret)
+		goto err_put_channels;
 
 	ret = device_add(&mhi_dev->dev);
 	if (ret)
-		put_device(&mhi_dev->dev);
+		goto err_put_channels;
+
+	return 0;
+
+err_put_channels:
+	put_device(&mhi_dev->dev); /* DL channel reference */
+	put_device(&mhi_dev->dev); /* UL channel reference */
+	put_device(&mhi_dev->dev); /* device_initialize() reference */
 
 	return ret;
 }
Signature · 1 line
2.53.0
author maintainer
#473 lore raw

PATCH 459/1376 iommu/mediatek-v1: Fix off-by-one in MT2701_LARB_NR_MAX

In reply to Greg Kroah-Hartman

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

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

From: Akari Tsuyukusa <[email protected]>

[ Upstream commit aebaa93f3da1572877579c2e15ebf27be2dcc7fb ]

The mt2701_m4u_in_larb[] array contains 4 (for LARB0 to LARB3) elements, meaning mt2701_m4u_to_larb() can legitimately return 3. The current check if (larbid >= MT2701_LARB_NR_MAX) incorrectly rejects valid LARB3 with -EINVAL.

Fix this off-by-one error by updating MT2701_LARB_NR_MAX to 4.

Note that this does not cause immediate issues with the current mt2701.dtsi and mt7623n.dtsi because it only defines 3 LARBs:

    mediatek,larbs = <&larb0 &larb1 &larb2>;

Thus, larbid never reaches 3 in the existing upstream device tree.

Fixes de78657e16f4 ("iommu/mediatek: Fix NULL pointer dereference when printing dev_name")
---
 drivers/iommu/mtk_iommu_v1.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/mtk_iommu_v1.c +1 -1
index 5a3eb7b587b45..378a09faa04c8 100644
@@ -78,7 +78,7 @@
 /* MTK generation one iommu HW only support 4K size mapping */
 #define MT2701_IOMMU_PAGE_SHIFT			12
 #define MT2701_IOMMU_PAGE_SIZE			(1UL << MT2701_IOMMU_PAGE_SHIFT)
-#define MT2701_LARB_NR_MAX			3
+#define MT2701_LARB_NR_MAX			4
 
 /*
  * MTK m4u support 4GB iova address space, and only support 4K page
Signature · 1 line
2.53.0
author maintainer
#474 lore raw

PATCH 460/1376 iommu/msm: Return -ENOMEM on memory allocation failure in probe

In reply to Greg Kroah-Hartman

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

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

From: Vladimir Zapolskiy <[email protected]>

[ Upstream commit b0d50c9016c4c2959dfa61bf9549cf98f9aa19cd ]

If dynamic memory allocation in driver's probe function execution fails, it should be reported to the driver's framework with -ENOMEM error code.

Fixes 109bd48ea2e1 ("iommu/msm: Add DT adaptation")
---
 drivers/iommu/msm_iommu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/msm_iommu.c +1 -1
index 989e0869d8055..036bacd162c72 100644
@@ -720,7 +720,7 @@ static int msm_iommu_probe(struct platform_device *pdev)
 
 	iommu = devm_kzalloc(&pdev->dev, sizeof(*iommu), GFP_KERNEL);
 	if (!iommu)
-		return -ENODEV;
+		return -ENOMEM;
 
 	iommu->dev = &pdev->dev;
 	INIT_LIST_HEAD(&iommu->ctx_list);
Signature · 1 line
2.53.0
author maintainer
#475 lore raw

PATCH 461/1376 iommu/amd: Prevent SB IOAPIC from overriding IVRS validation errors

In reply to Greg Kroah-Hartman

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

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

From: Wei Wang <[email protected]>

[ Upstream commit 854056480f9217568e3ab5edd81a9347a173ea79 ]

The check_ioapic_information() function validates IOAPICs against the IVRS table to safely disable Interrupt Remapping (IR) if the BIOS provides a broken topology.

Currently, the validation loop contains a bug: If an unmapped secondary IOAPIC is encountered, 'ret' is set to false. But if the Southbridge (SB) IOAPIC is enumerated after it in the MADT, the loop overwrites 'ret' to true.

This bypasses the validation failure and leaves IR enabled. When devices attached to the unmapped secondary IOAPIC fire interrupts, the IOMMU drops them due to the missing Requestor ID, leading to localized device hangs.

Fix this by initializing 'ret' to true and only toggling it to false upon encountering a validation error, ensuring failures are never erased.

Fixes c2ff5cf5294b ("iommu/amd: Work around wrong IOAPIC device-id in IVRS table")
---
 drivers/iommu/amd/init.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/iommu/amd/init.c +2 -2
index 54f3c17520d51..66f30e3883d57 100644
@@ -2973,7 +2973,7 @@ static bool __init check_ioapic_information(void)
 	int idx;
 
 	has_sb_ioapic = false;
-	ret           = false;
+	ret           = true;
 
 	/*
 	 * If we have map overrides on the kernel command line the
@@ -2993,7 +2993,6 @@ static bool __init check_ioapic_information(void)
 			ret = false;
 		} else if (devid == IOAPIC_SB_DEVID) {
 			has_sb_ioapic = true;
-			ret           = true;
 		}
 	}
 
@@ -3007,6 +3006,7 @@ static bool __init check_ioapic_information(void)
 		 * device id for the IOAPIC in the system.
 		 */
 		pr_err("%s: No southbridge IOAPIC found\n", fw_bug);
+		ret = false;
 	}
 
 	if (!ret)
Signature · 1 line
2.53.0
author maintainer
#476 lore raw

PATCH 462/1376 iommu/amd: Add support for Hygon family 18h model 4h IOAPIC

In reply to Greg Kroah-Hartman

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

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

From: Fu Hao <[email protected]>

[ Upstream commit 5beda8cadb1f072140e58b1edb7604444a42d955 ]

The SB IOAPIC is on the device 0xb from Hygon family 18h model 4h.

Stable-dep-of: 04fee302fac7 ("iommu/amd: Fix false positive in SB IOAPIC IVRS validation")

---
 drivers/iommu/amd/init.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/iommu/amd/init.c +9 -1
index 66f30e3883d57..d0ef7c936fd40 100644
@@ -2966,6 +2966,9 @@ static void __init free_iommu_resources(void)
 /* SB IOAPIC is always on this device in AMD systems */
 #define IOAPIC_SB_DEVID		((0x00 << 8) | PCI_DEVFN(0x14, 0))
 
+/* SB IOAPIC for Hygon family 18h model 4h is on the device 0xb */
+#define IOAPIC_SB_DEVID_FAM18H_M4H	((0x00 << 8) | PCI_DEVFN(0xb, 0))
+
 static bool __init check_ioapic_information(void)
 {
 	const char *fw_bug = FW_BUG;
@@ -2991,7 +2994,12 @@ static bool __init check_ioapic_information(void)
 			pr_err("%s: IOAPIC[%d] not in IVRS table\n",
 				fw_bug, id);
 			ret = false;
-		} else if (devid == IOAPIC_SB_DEVID) {
+		} else if (devid == IOAPIC_SB_DEVID ||
+			   (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON &&
+			    boot_cpu_data.x86 == 0x18 &&
+			    boot_cpu_data.x86_model >= 0x4 &&
+			    boot_cpu_data.x86_model <= 0xf &&
+			    devid == IOAPIC_SB_DEVID_FAM18H_M4H)) {
 			has_sb_ioapic = true;
 		}
 	}
Signature · 1 line
2.53.0
author maintainer
#477 lore raw

PATCH 463/1376 iommu/amd: Fix false positive in SB IOAPIC IVRS validation

In reply to Greg Kroah-Hartman

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

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

From: Wei Wang <[email protected]>

[ Upstream commit 04fee302fac762a242ff1ad6810cff90c2a350ba ]

The check_ioapic_information() function is designed to prevent boot hangs by ensuring the Southbridge (SB) IOAPIC is properly mapped in the IVRS table before enabling Interrupt Remapping.

Currently, this check passes if *any* enumerated IOAPIC matches the expected SB IOAPIC device ID. If a buggy BIOS incorrectly assigns the SB IOAPIC's device ID to a secondary IOAPIC in the IVRS, while scrambling the true SB IOAPIC's mapping, the check hits a false positive and succeeds.

This erroneously enables Interrupt Remapping. Consequently, the IOMMU blocks unmapped interrupts from the actual SB IOAPIC, dropping the system timer and leading to a silent kernel boot hang.

Tighten the validation to verify the device ID specifically against the SB IOAPIC by matching their APIC IDs first. This prevents the validation check from being bypassed via device ID aliasing.

Fixes c2ff5cf5294b ("iommu/amd: Work around wrong IOAPIC device-id in IVRS table")
---
 drivers/iommu/amd/init.c | 32 ++++++++++++++++++++++++++++----
 1 file changed, 28 insertions(+), 4 deletions(-)
drivers/iommu/amd/init.c +28 -4
index d0ef7c936fd40..b9a14c3ef4402 100644
@@ -2969,11 +2969,25 @@ static void __init free_iommu_resources(void)
 /* SB IOAPIC for Hygon family 18h model 4h is on the device 0xb */
 #define IOAPIC_SB_DEVID_FAM18H_M4H	((0x00 << 8) | PCI_DEVFN(0xb, 0))
 
+/*
+ * The Southbridge IOAPIC is assigned a GSI Base of 0 (handling interrupts
+ * 0 through 23).
+ */
+static int __init get_sb_ioapic_id(void)
+{
+	int idx = mp_find_ioapic(0);
+
+	if (idx < 0)
+		return -ENODEV;
+
+	return mpc_ioapic_id(idx);
+}
+
 static bool __init check_ioapic_information(void)
 {
 	const char *fw_bug = FW_BUG;
 	bool ret, has_sb_ioapic;
-	int idx;
+	int idx, sb_apicid;
 
 	has_sb_ioapic = false;
 	ret           = true;
@@ -2986,6 +3000,16 @@ static bool __init check_ioapic_information(void)
 	if (cmdline_maps)
 		fw_bug = "";
 
+	sb_apicid = get_sb_ioapic_id();
+	if (sb_apicid < 0) {
+		/*
+		 * Lack of SB IOAPIC registration is not a firmware bug,
+		 * e.g. kernel booted with noapic or noacpi.
+		 */
+		fw_bug = "";
+		goto out;
+	}
+
 	for (idx = 0; idx < nr_ioapics; idx++) {
 		int devid, id = mpc_ioapic_id(idx);
 
@@ -2994,16 +3018,16 @@ static bool __init check_ioapic_information(void)
 			pr_err("%s: IOAPIC[%d] not in IVRS table\n",
 				fw_bug, id);
 			ret = false;
-		} else if (devid == IOAPIC_SB_DEVID ||
+		} else if (id == sb_apicid && (devid == IOAPIC_SB_DEVID ||
 			   (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON &&
 			    boot_cpu_data.x86 == 0x18 &&
 			    boot_cpu_data.x86_model >= 0x4 &&
 			    boot_cpu_data.x86_model <= 0xf &&
-			    devid == IOAPIC_SB_DEVID_FAM18H_M4H)) {
+			    devid == IOAPIC_SB_DEVID_FAM18H_M4H))) {
 			has_sb_ioapic = true;
 		}
 	}
-
+out:
 	if (!has_sb_ioapic) {
 		/*
 		 * We expect the SB IOAPIC to be listed in the IVRS
Signature · 1 line
2.53.0
author maintainer
#478 lore raw

PATCH 464/1376 leds: pca9532: Fix inverted GPIO output polarity

In reply to Greg Kroah-Hartman

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

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

From: Cosmo Chou <[email protected]>

[ Upstream commit 65a38a28a0b04af19a5e1fbf3869051412eeac96 ]

The pca9532_gpio_set_value() function incorrectly mapped the requested value to PCA9532_ON and PCA9532_OFF, inverting the GPIO output polarity. A requested logical high (val=1) incorrectly enabled the LED output driver, which on this open-drain device pulls the pin low, while a requested logical low (val=0) released the pin.

Correct the mapping so that val=1 yields PCA9532_OFF (pin released / high-impedance) and val=0 yields PCA9532_ON (pin driven low).

pca9532_gpio_direction_input() is also updated to pass val=1 to pca9532_gpio_set_value() to align with the corrected polarity mapping, ensuring the pin remains not driven when configured as an input.

Fixes 3c1ab50d0a31 ("drivers/leds/leds-pca9532.c: add gpio capability")
---
 drivers/leds/leds-pca9532.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/leds/leds-pca9532.c +3 -3
index 1b47acf54720b..66ed6a77961ad 100644
@@ -324,9 +324,9 @@ static void pca9532_gpio_set_value(struct gpio_chip *gc, unsigned offset, int va
 	struct pca9532_led *led = &data->leds[offset];
 
 	if (val)
-		led->state = PCA9532_ON;
-	else
 		led->state = PCA9532_OFF;
+	else
+		led->state = PCA9532_ON;
 
 	pca9532_setled(led);
 }
@@ -344,7 +344,7 @@ static int pca9532_gpio_get_value(struct gpio_chip *gc, unsigned offset)
 static int pca9532_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
 {
 	/* To use as input ensure pin is not driven */
-	pca9532_gpio_set_value(gc, offset, 0);
+	pca9532_gpio_set_value(gc, offset, 1);
 
 	return 0;
 }
Signature · 1 line
2.53.0
author maintainer
#479 lore raw

PATCH 465/1376 printk/panic: Add option to allow non-panic CPUs to write to the ring buffer.

In reply to Greg Kroah-Hartman

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

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

From: Donghyeok Choe <[email protected]>

[ Upstream commit c1aa3daa517292303d98ff61f0440c354669f948 ]

Commit 779dbc2e78d7 ("printk: Avoid non-panic CPUs writing to ringbuffer") aimed to isolate panic-related messages. However, when panic() itself malfunctions, messages from non-panic CPUs become crucial for debugging.

While commit bcc954c6caba ("printk/panic: Allow cpu backtraces to be written into ringbuffer during panic") enables non-panic CPU backtraces, it may not provide sufficient diagnostic information.

Introduce the "debug_non_panic_cpus" command-line option, enabling non-panic CPU messages to be stored in the ring buffer during a panic. This also prevents discarding non-finalized messages from non-panic CPUs during console flushing, providing a more comprehensive view of system state during critical failures.

Stable-dep-of: 36630cafbeed ("printk: Fix possible console use-after-free")

---
 .../admin-guide/kernel-parameters.txt         |  8 ++++++++
 kernel/printk/internal.h                      |  1 +
 kernel/printk/printk.c                        | 20 ++++++++++++++++++-
 kernel/printk/printk_ringbuffer.c             | 13 +++++++-----
 4 files changed, 36 insertions(+), 6 deletions(-)
Documentation/admin-guide/kernel-parameters.txt +8 -0
index be2957b10d0b0..886095f45290e 100644
@@ -4860,6 +4860,14 @@
 			Format: <bool>
 			default: 0 (auto_verbose is enabled)
 
+	printk.debug_non_panic_cpus=
+			Allows storing messages from non-panic CPUs into
+			the printk log buffer during panic(). They are
+			flushed to consoles by the panic-CPU on
+			a best-effort basis.
+			Format: <bool> (1/Y/y=enable, 0/N/n=disable)
+			Default: disabled
+
 	printk.devkmsg={on,off,ratelimit}
 			Control writing to /dev/kmsg.
 			on - unlimited logging to /dev/kmsg from userspace
kernel/printk/internal.h +1 -0
index 5eef70000b439..2cc13c5597688 100644
@@ -62,6 +62,7 @@ struct dev_printk_info;
 
 extern struct printk_ringbuffer *prb;
 extern bool printk_kthreads_running;
+extern bool debug_non_panic_cpus;
 
 __printf(4, 0)
 int vprintk_store(int facility, int level,
kernel/printk/printk.c +19 -1
index 3a91b739e8f30..aa5c3e91ffd54 100644
@@ -2350,6 +2350,22 @@ void printk_legacy_allow_panic_sync(void)
 	}
 }
 
+bool __read_mostly debug_non_panic_cpus;
+
+#ifdef CONFIG_PRINTK_CALLER
+static int __init debug_non_panic_cpus_setup(char *str)
+{
+	debug_non_panic_cpus = true;
+	pr_info("allow messages from non-panic CPUs in panic()\n");
+
+	return 0;
+}
+early_param("debug_non_panic_cpus", debug_non_panic_cpus_setup);
+module_param(debug_non_panic_cpus, bool, 0644);
+MODULE_PARM_DESC(debug_non_panic_cpus,
+		 "allow messages from non-panic CPUs in panic()");
+#endif
+
 asmlinkage int vprintk_emit(int facility, int level,
 			    const struct dev_printk_info *dev_info,
 			    const char *fmt, va_list args)
@@ -2366,7 +2382,9 @@ asmlinkage int vprintk_emit(int facility, int level,
 	 * non-panic CPUs are generating any messages, they will be
 	 * silently dropped.
 	 */
-	if (other_cpu_in_panic() && !panic_triggering_all_cpu_backtrace)
+	if (other_cpu_in_panic() &&
+	    !debug_non_panic_cpus &&
+	    !panic_triggering_all_cpu_backtrace)
 		return 0;
 
 	printk_get_console_flush_type(&ft);
kernel/printk/printk_ringbuffer.c +8 -5
index 88e8f3a619229..d9fb053cff67d 100644
@@ -2133,9 +2133,9 @@ static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq,
 			 * there may be other finalized records beyond that
 			 * need to be printed for a panic situation. If this
 			 * is the panic CPU, skip this
-			 * non-existent/non-finalized record unless it is
-			 * at or beyond the head, in which case it is not
-			 * possible to continue.
+			 * non-existent/non-finalized record unless non-panic
+			 * CPUs are still running and their debugging is
+			 * explicitly enabled.
 			 *
 			 * Note that new messages printed on panic CPU are
 			 * finalized when we are here. The only exception
@@ -2143,10 +2143,13 @@ static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq,
 			 * But it would have the sequence number returned
 			 * by "prb_next_reserve_seq() - 1".
 			 */
-			if (this_cpu_in_panic() && ((*seq + 1) < prb_next_reserve_seq(rb)))
+			if (this_cpu_in_panic() &&
+			    (!debug_non_panic_cpus || legacy_allow_panic_sync) &&
+			    ((*seq + 1) < prb_next_reserve_seq(rb))) {
 				(*seq)++;
-			else
+			} else {
 				return false;
+			}
 		}
 	}
 
Signature · 1 line
2.53.0
author maintainer
#480 lore raw

PATCH 466/1376 panic: introduce helper functions for panic state

In reply to Greg Kroah-Hartman

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

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

From: Jinchao Wang <[email protected]>

[ Upstream commit d0d9c7235548f1d772f1e48c9d5742c65d81c705 ]

Patch series "panic: introduce panic status function family", v2.

This series introduces a family of helper functions to manage panic state and updates existing code to use them.

Before this series, panic state helpers were scattered and inconsistent. For example, panic_in_progress() was defined in printk/printk.c, not in panic.c or panic.h. As a result, developers had to look in unexpected places to understand or re-use panic state logic. Other checks were open- coded, duplicating logic across panic, crash, and watchdog paths.

The new helpers centralize the functionality in panic.c/panic.h:
- panic_try_start()
- panic_reset()
- panic_in_progress()
- panic_on_this_cpu()
- panic_on_other_cpu()

Patches 1–8 add the helpers and convert panic/crash and printk/nbcon code to use them.

Patch 9 fixes a bug in the watchdog subsystem by skipping checks when a panic is in progress, avoiding interference with the panic CPU.

Together, this makes panic state handling simpler, more discoverable, and more robust.

This patch (of 9):

This patch introduces four new helper functions to abstract the management of the panic_cpu variable. These functions will be used in subsequent patches to refactor existing code.

The direct use of panic_cpu can be error-prone and ambiguous, as it requires manual checks to determine which CPU is handling the panic. The new helpers clarify intent:

panic_try_start():
Atomically sets the current CPU as the panicking CPU.

panic_reset():
Reset panic_cpu to PANIC_CPU_INVALID.

panic_in_progress():
Checks if a panic has been triggered.

panic_on_this_cpu():
Returns true if the current CPU is the panic originator.

panic_on_other_cpu():
Returns true if a panic is on another CPU.

This change lays the groundwork for improved code readability and robustness in the panic handling subsystem.

Cc Anna Schumaker <[email protected]>
Cc Baoquan He <[email protected]>
Cc "Darrick J. Wong" <[email protected]>
Cc Dave Young <[email protected]>
Cc Doug Anderson <[email protected]>
Cc "Guilherme G. Piccoli" <[email protected]>
Cc Helge Deller <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Jason Gunthorpe <[email protected]>
Cc Joanthan Cameron <[email protected]>
Cc Joel Granados <[email protected]>
Cc John Ogness <[email protected]>
Cc Kees Cook <[email protected]>
Cc Li Huafei <[email protected]>
Cc "Luck, Tony" <[email protected]>
Cc Luo Gengkun <[email protected]>
Cc Max Kellermann <[email protected]>
Cc Nam Cao <[email protected]>
Cc oushixiong <[email protected]>
Cc Petr Mladek <[email protected]>
Cc Qianqiang Liu <[email protected]>
Cc Sergey Senozhatsky <[email protected]>
Cc Sohil Mehta <[email protected]>
Cc Steven Rostedt <[email protected]>
Cc Tejun Heo <[email protected]>
Cc Thomas Gleinxer <[email protected]>
Cc Thomas Zimemrmann <[email protected]>
Cc Thorsten Blum <[email protected]>
Cc Ville Syrjala <[email protected]>
Cc Vivek Goyal <[email protected]>
Cc Yicong Yang <[email protected]>
Cc Yunhui Cui <[email protected]>
Cc Yury Norov (NVIDIA) <[email protected]>b

Stable-dep-of: 36630cafbeed ("printk: Fix possible console use-after-free")

---
 include/linux/panic.h  |  6 +++++
 kernel/panic.c         | 53 ++++++++++++++++++++++++++++++++++++++++++
 kernel/printk/printk.c |  5 ----
 3 files changed, 59 insertions(+), 5 deletions(-)
include/linux/panic.h +6 -0
index 54d90b6c5f47b..f0b779d2915e6 100644
@@ -44,6 +44,12 @@ void abort(void);
 extern atomic_t panic_cpu;
 #define PANIC_CPU_INVALID	-1
 
+bool panic_try_start(void);
+void panic_reset(void);
+bool panic_in_progress(void);
+bool panic_on_this_cpu(void);
+bool panic_on_other_cpu(void);
+
 /*
  * Only to be used by arch init code. If the user over-wrote the default
  * CONFIG_PANIC_TIMEOUT, honor it.
kernel/panic.c +53 -0

59 lines not on this page · raw message

kernel/printk/printk.c +0 -5
index aa5c3e91ffd54..7b7f0fd6adc7f 100644
@@ -345,11 +345,6 @@ static void __up_console_sem(unsigned long ip)
 }
 #define up_console_sem() __up_console_sem(_RET_IP_)
 
-static bool panic_in_progress(void)
-{
-	return unlikely(atomic_read(&panic_cpu) != PANIC_CPU_INVALID);
-}
-
 /* Return true if a panic is in progress on the current CPU. */
 bool this_cpu_in_panic(void)
 {
Signature · 1 line
2.53.0
author maintainer
#481 lore raw

PATCH 467/1376 panic/printk: replace this_cpu_in_panic() with panic_on_this_cpu()

In reply to Greg Kroah-Hartman

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

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

From: Jinchao Wang <[email protected]>

[ Upstream commit c6be36e2997662f423edfa3979a63935873ff648 ]

The helper this_cpu_in_panic() duplicated logic already provided by panic_on_this_cpu().

Remove this_cpu_in_panic() and switch all users to panic_on_this_cpu().

This simplifies the code and avoids having two helpers for the same check.

Cc Anna Schumaker <[email protected]>
Cc Baoquan He <[email protected]>
Cc "Darrick J. Wong" <[email protected]>
Cc Dave Young <[email protected]>
Cc Doug Anderson <[email protected]>
Cc "Guilherme G. Piccoli" <[email protected]>
Cc Helge Deller <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Jason Gunthorpe <[email protected]>
Cc Joanthan Cameron <[email protected]>
Cc Joel Granados <[email protected]>
Cc John Ogness <[email protected]>
Cc Kees Cook <[email protected]>
Cc Li Huafei <[email protected]>
Cc "Luck, Tony" <[email protected]>
Cc Luo Gengkun <[email protected]>
Cc Max Kellermann <[email protected]>
Cc Nam Cao <[email protected]>
Cc oushixiong <[email protected]>
Cc Petr Mladek <[email protected]>
Cc Qianqiang Liu <[email protected]>
Cc Sergey Senozhatsky <[email protected]>
Cc Sohil Mehta <[email protected]>
Cc Steven Rostedt <[email protected]>
Cc Tejun Heo <[email protected]>
Cc Thomas Gleinxer <[email protected]>
Cc Thomas Zimemrmann <[email protected]>
Cc Thorsten Blum <[email protected]>
Cc Ville Syrjala <[email protected]>
Cc Vivek Goyal <[email protected]>
Cc Yicong Yang <[email protected]>
Cc Yunhui Cui <[email protected]>
Cc Yury Norov (NVIDIA) <[email protected]>

Stable-dep-of: 36630cafbeed ("printk: Fix possible console use-after-free")

---
 include/linux/printk.h            |  2 --
 kernel/panic.c                    |  2 +-
 kernel/printk/nbcon.c             |  2 +-
 kernel/printk/printk.c            | 15 ++-------------
 kernel/printk/printk_ringbuffer.c |  2 +-
 lib/dump_stack.c                  |  2 +-
 6 files changed, 6 insertions(+), 19 deletions(-)
include/linux/printk.h +0 -2
index a6c6fd107805b..c2ae39c85a203 100644
@@ -312,8 +312,6 @@ static inline bool pr_flush(int timeout_ms, bool reset_on_progress)
 
 #endif
 
-bool this_cpu_in_panic(void);
-
 #ifdef CONFIG_SMP
 extern int __printk_cpu_sync_try_get(void);
 extern void __printk_cpu_sync_wait(void);
kernel/panic.c +1 -1
index b4005d5d3343a..97c472164393b 100644
@@ -236,7 +236,7 @@ EXPORT_SYMBOL(panic_on_this_cpu);
  */
 bool panic_on_other_cpu(void)
 {
-	return (panic_in_progress() && !this_cpu_in_panic());
+	return (panic_in_progress() && !panic_on_this_cpu());
 }
 EXPORT_SYMBOL(panic_on_other_cpu);
 
kernel/printk/nbcon.c +1 -1
index e7a3af81b1739..68563ed55e203 100644
@@ -1394,7 +1394,7 @@ enum nbcon_prio nbcon_get_default_prio(void)
 {
 	unsigned int *cpu_emergency_nesting;
 
-	if (this_cpu_in_panic())
+	if (panic_on_this_cpu())
 		return NBCON_PRIO_PANIC;
 
 	cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting();
kernel/printk/printk.c +2 -13
index 7b7f0fd6adc7f..a01a5683ecd92 100644
@@ -17,6 +17,7 @@
  *	01Mar01 Andrew Morton
  */
 
+#include "linux/panic.h"
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
@@ -345,18 +346,6 @@ static void __up_console_sem(unsigned long ip)
 }
 #define up_console_sem() __up_console_sem(_RET_IP_)
 
-/* Return true if a panic is in progress on the current CPU. */
-bool this_cpu_in_panic(void)
-{
-	/*
-	 * We can use raw_smp_processor_id() here because it is impossible for
-	 * the task to be migrated to the panic_cpu, or away from it. If
-	 * panic_cpu has already been set, and we're not currently executing on
-	 * that CPU, then we never will be.
-	 */
-	return unlikely(atomic_read(&panic_cpu) == raw_smp_processor_id());
-}
-
 /*
  * Return true if a panic is in progress on a remote CPU.
  *
@@ -365,7 +354,7 @@ bool this_cpu_in_panic(void)
  */
 bool other_cpu_in_panic(void)
 {
-	return (panic_in_progress() && !this_cpu_in_panic());
+	return (panic_in_progress() && !panic_on_this_cpu());
 }
 
 /*
kernel/printk/printk_ringbuffer.c +1 -1
index d9fb053cff67d..e2a1b2d34d2b7 100644
@@ -2143,7 +2143,7 @@ static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq,
 			 * But it would have the sequence number returned
 			 * by "prb_next_reserve_seq() - 1".
 			 */
-			if (this_cpu_in_panic() &&
+			if (panic_on_this_cpu() &&
 			    (!debug_non_panic_cpus || legacy_allow_panic_sync) &&
 			    ((*seq + 1) < prb_next_reserve_seq(rb))) {
 				(*seq)++;
lib/dump_stack.c +1 -1
index 388da1aea14a5..0b41b0a34323c 100644
@@ -102,7 +102,7 @@ static void __dump_stack(const char *log_lvl)
  */
 asmlinkage __visible void dump_stack_lvl(const char *log_lvl)
 {
-	bool in_panic = this_cpu_in_panic();
+	bool in_panic = panic_on_this_cpu();
 	unsigned long flags;
 
 	/*
Signature · 1 line
2.53.0
author maintainer
#482 lore raw

PATCH 468/1376 panic/printk: replace other_cpu_in_panic() with panic_on_other_cpu()

In reply to Greg Kroah-Hartman

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

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

From: Jinchao Wang <[email protected]>

[ Upstream commit d4a36db5639db032a434aef968f9188a600139ec ]

The helper other_cpu_in_panic() duplicated logic already provided by panic_on_other_cpu().

Remove other_cpu_in_panic() and update all users to call panic_on_other_cpu() instead.

This removes redundant code and makes panic handling consistent.

Cc Anna Schumaker <[email protected]>
Cc Baoquan He <[email protected]>
Cc "Darrick J. Wong" <[email protected]>
Cc Dave Young <[email protected]>
Cc Doug Anderson <[email protected]>
Cc "Guilherme G. Piccoli" <[email protected]>
Cc Helge Deller <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Jason Gunthorpe <[email protected]>
Cc Joanthan Cameron <[email protected]>
Cc Joel Granados <[email protected]>
Cc John Ogness <[email protected]>
Cc Kees Cook <[email protected]>
Cc Li Huafei <[email protected]>
Cc "Luck, Tony" <[email protected]>
Cc Luo Gengkun <[email protected]>
Cc Max Kellermann <[email protected]>
Cc Nam Cao <[email protected]>
Cc oushixiong <[email protected]>
Cc Petr Mladek <[email protected]>
Cc Qianqiang Liu <[email protected]>
Cc Sergey Senozhatsky <[email protected]>
Cc Sohil Mehta <[email protected]>
Cc Steven Rostedt <[email protected]>
Cc Tejun Heo <[email protected]>
Cc Thomas Gleinxer <[email protected]>
Cc Thomas Zimemrmann <[email protected]>
Cc Thorsten Blum <[email protected]>
Cc Ville Syrjala <[email protected]>
Cc Vivek Goyal <[email protected]>
Cc Yicong Yang <[email protected]>
Cc Yunhui Cui <[email protected]>
Cc Yury Norov (NVIDIA) <[email protected]>

Stable-dep-of: 36630cafbeed ("printk: Fix possible console use-after-free")

---
 kernel/printk/internal.h |  1 -
 kernel/printk/nbcon.c    |  8 ++++----
 kernel/printk/printk.c   | 19 ++++---------------
 3 files changed, 8 insertions(+), 20 deletions(-)
kernel/printk/internal.h +0 -1
index 2cc13c5597688..53c4b3438a1c6 100644
@@ -328,7 +328,6 @@ struct printk_message {
 	unsigned long		dropped;
 };
 
-bool other_cpu_in_panic(void);
 bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
 			     bool is_extended, bool may_supress);
 
kernel/printk/nbcon.c +4 -4
index 68563ed55e203..7b4dcb09ce998 100644
@@ -254,7 +254,7 @@ static int nbcon_context_try_acquire_direct(struct nbcon_context *ctxt,
 		 * opportunity to perform any necessary cleanup if they were
 		 * interrupted by the panic CPU while printing.
 		 */
-		if (other_cpu_in_panic() &&
+		if (panic_on_other_cpu() &&
 		    (!is_reacquire || cur->unsafe_takeover)) {
 			return -EPERM;
 		}
@@ -309,7 +309,7 @@ static bool nbcon_waiter_matches(struct nbcon_state *cur, int expected_prio)
 	 * Event #2 implies the new context is PANIC.
 	 * Event #3 occurs when panic() has flushed the console.
 	 * Event #4 occurs when a non-panic CPU reacquires.
-	 * Event #5 is not possible due to the other_cpu_in_panic() check
+	 * Event #5 is not possible due to the panic_on_other_cpu() check
 	 *          in nbcon_context_try_acquire_handover().
 	 */
 
@@ -348,7 +348,7 @@ static int nbcon_context_try_acquire_requested(struct nbcon_context *ctxt,
 	struct nbcon_state new;
 
 	/* Note that the caller must still remove the request! */
-	if (other_cpu_in_panic())
+	if (panic_on_other_cpu())
 		return -EPERM;
 
 	/*
@@ -446,7 +446,7 @@ static int nbcon_context_try_acquire_handover(struct nbcon_context *ctxt,
 	 * nbcon_waiter_matches(). In particular, the assumption that
 	 * lower priorities are ignored during panic.
 	 */
-	if (other_cpu_in_panic())
+	if (panic_on_other_cpu())
 		return -EPERM;
 
 	/* Handover is not possible on the same CPU. */
kernel/printk/printk.c +4 -15
index a01a5683ecd92..9434460cff640 100644
@@ -346,17 +346,6 @@ static void __up_console_sem(unsigned long ip)
 }
 #define up_console_sem() __up_console_sem(_RET_IP_)
 
-/*
- * Return true if a panic is in progress on a remote CPU.
- *
- * On true, the local CPU should immediately release any printing resources
- * that may be needed by the panic CPU.
- */
-bool other_cpu_in_panic(void)
-{
-	return (panic_in_progress() && !panic_on_this_cpu());
-}
-
 /*
  * This is used for debugging the mess that is the VT code by
  * keeping track if we have the console semaphore held. It's
@@ -2366,7 +2355,7 @@ asmlinkage int vprintk_emit(int facility, int level,
 	 * non-panic CPUs are generating any messages, they will be
 	 * silently dropped.
 	 */
-	if (other_cpu_in_panic() &&
+	if (panic_on_other_cpu() &&
 	    !debug_non_panic_cpus &&
 	    !panic_triggering_all_cpu_backtrace)
 		return 0;
@@ -2802,7 +2791,7 @@ void console_lock(void)
 	might_sleep();
 
 	/* On panic, the console_lock must be left to the panic cpu. */
-	while (other_cpu_in_panic())
+	while (panic_on_other_cpu())
 		msleep(1000);
 
 	down_console_sem();
@@ -2822,7 +2811,7 @@ EXPORT_SYMBOL(console_lock);
 int console_trylock(void)
 {
 	/* On panic, the console_lock must be left to the panic cpu. */
-	if (other_cpu_in_panic())
+	if (panic_on_other_cpu())
 		return 0;
 	if (down_trylock_console_sem())
 		return 0;
@@ -3197,7 +3186,7 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
 			any_progress = true;
 
 			/* Allow panic_cpu to take over the consoles safely. */
-			if (other_cpu_in_panic())
+			if (panic_on_other_cpu())
 				goto abandon;
 
 			if (do_cond_resched)
Signature · 1 line
2.53.0
author maintainer
#483 lore raw

PATCH 469/1376 printk: Introduce console_flush_one_record

In reply to Greg Kroah-Hartman

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

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

From: Andrew Murray <[email protected]>

[ Upstream commit 741ea7aa95dd9ac77f861e7d0961d8d231ac8448 ]

console_flush_all prints all remaining records to all usable consoles whilst its caller holds console_lock. This can result in large waiting times for those waiting for console_lock especially where there is a large volume of records or where the console is slow (e.g. serial).

Let's extract the parts of this function which print a single record into a new function named console_flush_one_record. This can later be used for functions that will release and reacquire console_lock between records.

This commit should not change existing functionality.

Stable-dep-of: 36630cafbeed ("printk: Fix possible console use-after-free")

---
 kernel/printk/printk.c | 158 ++++++++++++++++++++++++++---------------
 1 file changed, 99 insertions(+), 59 deletions(-)
kernel/printk/printk.c +99 -59
index 9434460cff640..464227c82b08d 100644
@@ -3104,6 +3104,99 @@ static inline void printk_kthreads_check_locked(void) { }
 
 #endif /* CONFIG_PRINTK */
 
+
+/*
+ * Print out one record for each console.
+ *
+ * @do_cond_resched is set by the caller. It can be true only in schedulable
+ * context.
+ *
+ * @next_seq is set to the sequence number after the last available record.
+ * The value is valid only when there is at least one usable console and all
+ * usable consoles were flushed.
+ *
+ * @handover will be set to true if a printk waiter has taken over the
+ * console_lock, in which case the caller is no longer holding the
+ * console_lock. Otherwise it is set to false.
+ *
+ * @any_usable will be set to true if there are any usable consoles.
+ *
+ * Returns true when there was at least one usable console and a record was
+ * flushed. A returned false indicates there were no records to flush for any
+ * of the consoles. It may also indicate that there were no usable consoles,
+ * the context has been lost or there is a panic suitation. Regardless the
+ * reason, the caller should assume it is not useful to immediately try again.
+ *
+ * Requires the console_lock.
+ */
+static bool console_flush_one_record(bool do_cond_resched, u64 *next_seq, bool *handover,
+				     bool *any_usable)
+{
+	struct console_flush_type ft;
+	bool any_progress = false;
+	struct console *con;
+	int cookie;
+
+	printk_get_console_flush_type(&ft);
+
+	cookie = console_srcu_read_lock();
+	for_each_console_srcu(con) {
+		short flags = console_srcu_read_flags(con);
+		u64 printk_seq;
+		bool progress;
+
+		/*
+		 * console_flush_one_record() is only responsible for
+		 * nbcon consoles when the nbcon consoles cannot print via
+		 * their atomic or threaded flushing.
+		 */
+		if ((flags & CON_NBCON) && (ft.nbcon_atomic || ft.nbcon_offload))
+			continue;
+
+		if (!console_is_usable(con, flags, !do_cond_resched))
+			continue;
+		*any_usable = true;
+
+		if (flags & CON_NBCON) {
+			progress = nbcon_legacy_emit_next_record(con, handover, cookie,
+								 !do_cond_resched);
+			printk_seq = nbcon_seq_read(con);
+		} else {
+			progress = console_emit_next_record(con, handover, cookie);
+			printk_seq = con->seq;
+		}
+
+		/*
+		 * If a handover has occurred, the SRCU read lock
+		 * is already released.
+		 */
+		if (*handover)
+			return false;
+
+		/* Track the next of the highest seq flushed. */
+		if (printk_seq > *next_seq)
+			*next_seq = printk_seq;
+
+		if (!progress)
+			continue;
+		any_progress = true;
+
+		/* Allow panic_cpu to take over the consoles safely. */
+		if (panic_on_other_cpu())
+			goto abandon;
+
+		if (do_cond_resched)
+			cond_resched();
+	}
+	console_srcu_read_unlock(cookie);
+
+	return any_progress;
+
+abandon:
+	console_srcu_read_unlock(cookie);
+	return false;
+}
+
 /*
  * Print out all remaining records to all consoles.
  *
@@ -3129,77 +3222,24 @@ static inline void printk_kthreads_check_locked(void) { }
  */
 static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handover)
 {
-	struct console_flush_type ft;
 	bool any_usable = false;
-	struct console *con;
 	bool any_progress;
-	int cookie;
 
 	*next_seq = 0;
 	*handover = false;
 
 	do {
-		any_progress = false;
+		any_progress = console_flush_one_record(do_cond_resched, next_seq, handover,
+							&any_usable);
 
-		printk_get_console_flush_type(&ft);
-
-		cookie = console_srcu_read_lock();
-		for_each_console_srcu(con) {
-			short flags = console_srcu_read_flags(con);
-			u64 printk_seq;
-			bool progress;
+		if (*handover)
+			return false;
 
-			/*
-			 * console_flush_all() is only responsible for nbcon
-			 * consoles when the nbcon consoles cannot print via
-			 * their atomic or threaded flushing.
-			 */
-			if ((flags & CON_NBCON) && (ft.nbcon_atomic || ft.nbcon_offload))
-				continue;
-
-			if (!console_is_usable(con, flags, !do_cond_resched))
-				continue;
-			any_usable = true;
-
-			if (flags & CON_NBCON) {
-				progress = nbcon_legacy_emit_next_record(con, handover, cookie,
-									 !do_cond_resched);
-				printk_seq = nbcon_seq_read(con);
-			} else {
-				progress = console_emit_next_record(con, handover, cookie);
-				printk_seq = con->seq;
-			}
-
-			/*
-			 * If a handover has occurred, the SRCU read lock
-			 * is already released.
-			 */
-			if (*handover)
-				return false;
-
-			/* Track the next of the highest seq flushed. */
-			if (printk_seq > *next_seq)
-				*next_seq = printk_seq;
-
-			if (!progress)
-				continue;
-			any_progress = true;
-
-			/* Allow panic_cpu to take over the consoles safely. */
-			if (panic_on_other_cpu())
-				goto abandon;
-
-			if (do_cond_resched)
-				cond_resched();
-		}
-		console_srcu_read_unlock(cookie);
+		if (panic_on_other_cpu())
+			return false;
 	} while (any_progress);
 
 	return any_usable;
-
-abandon:
-	console_srcu_read_unlock(cookie);
-	return false;
 }
 
 static void __console_flush_and_unlock(void)
Signature · 1 line
2.53.0
author maintainer
#484 lore raw

PATCH 470/1376 printk: Fix possible console use-after-free

In reply to Greg Kroah-Hartman

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

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

From: John Ogness <[email protected]>

[ Upstream commit 36630cafbeede0b64c370edb2f7b4094327ee1e0 ]

When emitting a record via legacy printing, it is possible that a handover to another legacy printing context occurs. When a context has performed a handover, the console SRCU read lock is released and the pointer to the console struct might now be invalid. Therefore, after calling nbcon_legacy_emit_next_record() or console_emit_next_record(), it is necessary to check if a handover occurred _before_ further @con usage.

Sashiko pointed out that console_flush_one_record() was not doing this.

In console_flush_one_record(), after emitting a record, move the further usage of @con after the handover check.

---
 kernel/printk/printk.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)
kernel/printk/printk.c +9 -2
index 464227c82b08d..37f1d4637d90c 100644
@@ -3160,10 +3160,8 @@ static bool console_flush_one_record(bool do_cond_resched, u64 *next_seq, bool *
 		if (flags & CON_NBCON) {
 			progress = nbcon_legacy_emit_next_record(con, handover, cookie,
 								 !do_cond_resched);
-			printk_seq = nbcon_seq_read(con);
 		} else {
 			progress = console_emit_next_record(con, handover, cookie);
-			printk_seq = con->seq;
 		}
 
 		/*
@@ -3173,6 +3171,15 @@ static bool console_flush_one_record(bool do_cond_resched, u64 *next_seq, bool *
 		if (*handover)
 			return false;
 
+		/*
+		 * @con can be used here now that it is certain that this
+		 * context is still holding the SRCU read lock.
+		 */
+		if (flags & CON_NBCON)
+			printk_seq = nbcon_seq_read(con);
+		else
+			printk_seq = con->seq;
+
 		/* Track the next of the highest seq flushed. */
 		if (printk_seq > *next_seq)
 			*next_seq = printk_seq;
Signature · 1 line
2.53.0
author maintainer
#485 lore raw

PATCH 471/1376 ACPI: RISC-V: Fix riscv_acpi_irq_get_dep() loop termination

In reply to Greg Kroah-Hartman

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

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

From: Lorenzo Pieralisi <[email protected]>

[ Upstream commit 64ae310bffa477cd11029c818bec489f4b8a845e ]

In riscv_acpi_add_irq_dep() the main loop condition would currently stop the loop if an interrupt descriptor contains an interrupt for which the respective GSI handle is NULL, which is not correct because subsequent interrupts in the interrupt descriptor might still have a GSI dependency that must not be skipped.

Rework riscv_acpi_add_irq_dep() and the riscv_acpi_irq_get_dep() call chain to fix it - by not forcing the loop to stop in order to guarantee dependency detection for all the interrupt entries in the CRS descriptor.

---
 drivers/acpi/riscv/irq.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/acpi/riscv/irq.c +6 -4
index cced960c2aeff..e24266ce8a14f 100644
@@ -230,6 +230,7 @@ static acpi_status riscv_acpi_irq_get_parent(struct acpi_resource *ares, void *c
 			return AE_OK;
 
 		ctx->handle = riscv_acpi_get_gsi_handle(eirq->interrupts[ctx->index]);
+		ctx->rc = 0;
 		return AE_CTRL_TERMINATE;
 	}
 
@@ -245,10 +246,8 @@ static int riscv_acpi_irq_get_dep(acpi_handle handle, unsigned int index, acpi_h
 
 	acpi_walk_resources(handle, METHOD_NAME__CRS, riscv_acpi_irq_get_parent, &ctx);
 	*gsi_handle = ctx.handle;
-	if (*gsi_handle)
-		return 1;
 
-	return 0;
+	return ctx.rc;
 }
 
 static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
@@ -310,8 +309,11 @@ static u32 riscv_acpi_add_irq_dep(acpi_handle handle)
 	int i;
 
 	for (i = 0;
-	     riscv_acpi_irq_get_dep(handle, i, &gsi_handle);
+	     !riscv_acpi_irq_get_dep(handle, i, &gsi_handle);
 	     i++) {
+		if (!gsi_handle)
+			continue;
+
 		dep_devices.count = 1;
 		dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);
 		if (!dep_devices.handles) {
Signature · 1 line
2.53.0
author maintainer
#486 lore raw

PATCH 472/1376 ACPI: RISC-V: Check acpi_get_handle() status in riscv_acpi_add_prt_dep()

In reply to Greg Kroah-Hartman

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

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

From: Lorenzo Pieralisi <[email protected]>

[ Upstream commit 20435bda13f1219891ed0ce41207e320a916ff9c ]

In riscv_acpi_add_prt_dep(), the acpi_get_handle() call can fail which would leave link_handle uninitialized.

Fix it by checking the acpi_get_handle() return status and skip the entry if it fails.

---
 drivers/acpi/riscv/irq.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/acpi/riscv/irq.c +3 -1
index e24266ce8a14f..e97417ab94ce9 100644
@@ -270,7 +270,9 @@ static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
 	entry = buffer.pointer;
 	while (entry && (entry->length > 0)) {
 		if (entry->source[0]) {
-			acpi_get_handle(handle, entry->source, &link_handle);
+			status = acpi_get_handle(handle, entry->source, &link_handle);
+			if (ACPI_FAILURE(status))
+				continue;
 			dep_devices.count = 1;
 			dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);
 			if (!dep_devices.handles) {
Signature · 1 line
2.53.0
author maintainer
#487 lore raw

PATCH 473/1376 ACPI: RISC-V: Fix riscv_acpi_add_prt_dep() loop handling

In reply to Greg Kroah-Hartman

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

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

From: Lorenzo Pieralisi <[email protected]>

[ Upstream commit 3a56321d0aceee2a0bd80d23366401c131ff8350 ]

The loop in riscv_acpi_add_prt_dep() includes error conditions that are handled in a dubious - if not outright wrong - way, by continuining the loop (which skips and misses the entry pointer update to point to the next entry).

Rewrite the loop as a for loop (that handles the continuation correctly) and wrap the condition and update statements using helper functions to make it cleaner.

---
 drivers/acpi/riscv/irq.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)
drivers/acpi/riscv/irq.c +15 -4
index e97417ab94ce9..9c8185ca9f8c5 100644
@@ -250,6 +250,20 @@ static int riscv_acpi_irq_get_dep(acpi_handle handle, unsigned int index, acpi_h
 	return ctx.rc;
 }
 
+static bool acpi_prt_entry_valid(void *prt_entry)
+{
+	struct acpi_pci_routing_table *entry = prt_entry;
+
+	return entry && entry->length > 0;
+}
+
+static void *acpi_prt_next_entry(void *prt_entry)
+{
+	struct acpi_pci_routing_table *entry = prt_entry;
+
+	return prt_entry + entry->length;
+}
+
 static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
 {
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -268,7 +282,7 @@ static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
 	}
 
 	entry = buffer.pointer;
-	while (entry && (entry->length > 0)) {
+	for (; acpi_prt_entry_valid(entry); entry = acpi_prt_next_entry(entry)) {
 		if (entry->source[0]) {
 			status = acpi_get_handle(handle, entry->source, &link_handle);
 			if (ACPI_FAILURE(status))
@@ -294,9 +308,6 @@ static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
 			dep_devices.handles[0] = gsi_handle;
 			count += acpi_scan_add_dep(handle, &dep_devices);
 		}
-
-		entry = (struct acpi_pci_routing_table *)
-			((unsigned long)entry + entry->length);
 	}
 
 	kfree(buffer.pointer);
Signature · 1 line
2.53.0
author maintainer
#488 lore raw

PATCH 474/1376 platform/x86: dell-privacy: Fix race condition

In reply to Greg Kroah-Hartman

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

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

From: Armin Wolf <[email protected]>

[ Upstream commit ca9338dbc64759b30741b12017c050b33c94dfa2 ]

Accessing priv->features_present needs to happen with the list mutex being held, otherwise priv can be freed at any moment.

Fixes 8af9fa37b8a3 ("platform/x86: dell-privacy: Add support for Dell hardware privacy")
---
 drivers/platform/x86/dell/dell-wmi-privacy.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/platform/x86/dell/dell-wmi-privacy.c +2 -2
index 4b65e1655d42a..7c2b6fae96c52 100644
@@ -69,11 +69,11 @@ bool dell_privacy_has_mic_mute(void)
 {
 	struct privacy_wmi_data *priv;
 
-	mutex_lock(&list_mutex);
+	guard(mutex)(&list_mutex);
+
 	priv = list_first_entry_or_null(&wmi_list,
 			struct privacy_wmi_data,
 			list);
-	mutex_unlock(&list_mutex);
 
 	return priv && (priv->features_present & BIT(DELL_PRIVACY_TYPE_AUDIO));
 }
Signature · 1 line
2.53.0
author maintainer
#489 lore raw

PATCH 475/1376 platform/x86: dell-wmi-base: Fix resource leak on module load failure

In reply to Greg Kroah-Hartman

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

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

From: Armin Wolf <[email protected]>

[ Upstream commit 072841e02cf9c00a7e8a9c567a14239e02ca47ad ]

We need to properly clean up the SMBIOS request and the privacy driver when the module load fails.

Fixes 8af9fa37b8a3 ("platform/x86: dell-privacy: Add support for Dell hardware privacy")
---
 drivers/platform/x86/dell/dell-wmi-base.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)
drivers/platform/x86/dell/dell-wmi-base.c +15 -2
index 01f3ff21c8884..713ec2c12a04e 100644
@@ -839,9 +839,22 @@ static int __init dell_wmi_init(void)
 
 	err = dell_privacy_register_driver();
 	if (err)
-		return err;
+		goto out_smbios;
 
-	return wmi_driver_register(&dell_wmi_driver);
+	err = wmi_driver_register(&dell_wmi_driver);
+	if (err)
+		goto out_privacy;
+
+	return 0;
+
+out_privacy:
+	dell_privacy_unregister_driver();
+
+out_smbios:
+	if (wmi_requires_smbios_request)
+		dell_wmi_events_set_enabled(false);
+
+	return err;
 }
 late_initcall(dell_wmi_init);
 
Signature · 1 line
2.53.0
author maintainer
#490 lore raw

PATCH 476/1376 platform/x86: lg-laptop: Drop debug-only ACPI notify handler

In reply to Greg Kroah-Hartman

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

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

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

[ Upstream commit c12fe0b2c12195e0d1c56e0f670a6bd792b0567e ]

To facilitate subsequent conversion of the driver to using struct platform_driver instead of struct acpi_driver, drop the debug-only notify handler method from the driver.

No intentional functional impact beyond debug.

Stable-dep-of: 3e91964aa74a ("platform/x86: lg-laptop: Fix LED resource handling")

---
 drivers/platform/x86/lg-laptop.c | 6 ------
 1 file changed, 6 deletions(-)
drivers/platform/x86/lg-laptop.c +0 -6
index 6af6cf477c5b5..6a45e6270941a 100644
@@ -269,11 +269,6 @@ static void wmi_input_setup(void)
 	}
 }
 
-static void acpi_notify(struct acpi_device *device, u32 event)
-{
-	acpi_handle_debug(device->handle, "notify: %d\n", event);
-}
-
 static ssize_t fan_mode_store(struct device *dev,
 			      struct device_attribute *attr,
 			      const char *buffer, size_t count)
@@ -886,7 +881,6 @@ static struct acpi_driver acpi_driver = {
 	.ops = {
 		.add = acpi_add,
 		.remove = acpi_remove,
-		.notify = acpi_notify,
 		},
 };
 
Signature · 1 line
2.53.0
author maintainer
#491 lore raw

PATCH 477/1376 platform/x86: lg-laptop: Convert ACPI driver to a platform one

In reply to Greg Kroah-Hartman

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

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

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

[ Upstream commit 2d9cb20610f75ca48c1cac064aede90196787507 ]

In all cases in which a struct acpi_driver is used for binding a driver to an ACPI device object, a corresponding platform device is created by the ACPI core and that device is regarded as a proper representation of underlying hardware. Accordingly, a struct platform_driver should be used by driver code to bind to that device. There are multiple reasons why drivers should not bind directly to ACPI device objects [1].

Overall, it is better to bind drivers to platform devices than to their ACPI companions, so convert the LG Gram ACPI features and hotkeys driver from an ACPI driver to a platform one.

While this is not expected to alter functionality, it changes sysfs layout and so it will be visible to user space.

Stable-dep-of: 3e91964aa74a ("platform/x86: lg-laptop: Fix LED resource handling")

---
 drivers/platform/x86/lg-laptop.c | 45 +++++++++-----------------------
 1 file changed, 13 insertions(+), 32 deletions(-)
drivers/platform/x86/lg-laptop.c +13 -32
index 6a45e6270941a..a68c4867e696b 100644
@@ -748,8 +748,9 @@ static void lg_laptop_remove_address_space_handler(void *data)
 					  &lg_laptop_address_space_handler);
 }
 
-static int acpi_add(struct acpi_device *device)
+static int acpi_probe(struct platform_device *pdev)
 {
+	struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
 	struct platform_device_info pdev_info = {
 		.fwnode = acpi_fwnode_handle(device),
 		.name = PLATFORM_NAME,
@@ -765,11 +766,11 @@ static int acpi_add(struct acpi_device *device)
 
 	status = acpi_install_address_space_handler(device->handle, LG_ADDRESS_SPACE_ID,
 						    &lg_laptop_address_space_handler,
-						    NULL, &device->dev);
+						    NULL, &pdev->dev);
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	ret = devm_add_action_or_reset(&device->dev, lg_laptop_remove_address_space_handler,
+	ret = devm_add_action_or_reset(&pdev->dev, lg_laptop_remove_address_space_handler,
 				       device);
 	if (ret < 0)
 		return ret;
@@ -854,7 +855,7 @@ static int acpi_add(struct acpi_device *device)
 	return ret;
 }
 
-static void acpi_remove(struct acpi_device *device)
+static void acpi_remove(struct platform_device *pdev)
 {
 	sysfs_remove_group(&pf_device->dev.kobj, &dev_attribute_group);
 
@@ -874,33 +875,13 @@ static const struct acpi_device_id device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, device_ids);
 
-static struct acpi_driver acpi_driver = {
-	.name = "LG Gram Laptop Support",
-	.class = "lg-laptop",
-	.ids = device_ids,
-	.ops = {
-		.add = acpi_add,
-		.remove = acpi_remove,
-		},
+static struct platform_driver acpi_driver = {
+	.probe = acpi_probe,
+	.remove = acpi_remove,
+	.driver = {
+		.name = "LG Gram Laptop Support",
+		.acpi_match_table = device_ids,
+	},
 };
 
-static int __init acpi_init(void)
-{
-	int result;
-
-	result = acpi_bus_register_driver(&acpi_driver);
-	if (result < 0) {
-		pr_debug("Error registering driver\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static void __exit acpi_exit(void)
-{
-	acpi_bus_unregister_driver(&acpi_driver);
-}
-
-module_init(acpi_init);
-module_exit(acpi_exit);
+module_platform_driver(acpi_driver);
Signature · 1 line
2.53.0
author maintainer
#492 lore raw

PATCH 478/1376 platform/x86: lg-laptop: Fix LED resource handling

In reply to Greg Kroah-Hartman

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

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

From: Armin Wolf <[email protected]>

[ Upstream commit 3e91964aa74ab261aa15d9d96318eded2fd9d22a ]

The event notification callback might access kbd_backlight even when it was not successfully registered with the LED subsystem. The same happens inside acpi_remove(), where the LED devices are unregistered unconditionally.

Fix this by tracking the availability of the kbd_backlight LED device and use devm_led_classdev_register() to let devres take care of unregistering the LED devices during removal. For this the parent device of the LED devices is changed to the native platform device.

Fixes ae26278829a8 ("platform/x86: lg-laptop: Use correct event for keyboard backlight FN-key")
---
 drivers/platform/x86/lg-laptop.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)
drivers/platform/x86/lg-laptop.c +14 -7
index a68c4867e696b..0a5c8f0471823 100644
@@ -98,6 +98,7 @@ static u32 inited;
 #define INIT_SPARSE_KEYMAP      0x80
 
 static int battery_limit_use_wmbb;
+static bool kbd_backlight_available;
 static struct led_classdev kbd_backlight;
 static enum led_brightness get_kbd_backlight_level(struct device *dev);
 
@@ -212,6 +213,7 @@ static union acpi_object *lg_wmbb(struct device *dev, u32 method_id, u32 arg1, u
 static void wmi_notify(union acpi_object *obj, void *context)
 {
 	long data = (long)context;
+	unsigned int brightness;
 
 	pr_debug("event guid %li\n", data);
 	if (!obj)
@@ -222,8 +224,11 @@ static void wmi_notify(union acpi_object *obj, void *context)
 		struct key_entry *key;
 
 		if (eventcode == 0x10000000) {
-			led_classdev_notify_brightness_hw_changed(
-				&kbd_backlight, get_kbd_backlight_level(kbd_backlight.dev->parent));
+			if (kbd_backlight_available) {
+				brightness = get_kbd_backlight_level(kbd_backlight.dev->parent);
+				led_classdev_notify_brightness_hw_changed(&kbd_backlight,
+									  brightness);
+			}
 		} else {
 			key = sparse_keymap_entry_from_scancode(
 				wmi_input_dev, eventcode);
@@ -840,8 +845,13 @@ static int acpi_probe(struct platform_device *pdev)
 		goto out_platform_device;
 
 	/* LEDs are optional */
-	led_classdev_register(&pf_device->dev, &kbd_backlight);
-	led_classdev_register(&pf_device->dev, &tpad_led);
+	ret = devm_led_classdev_register(&pdev->dev, &kbd_backlight);
+	if (ret < 0)
+		kbd_backlight_available = false;
+	else
+		kbd_backlight_available = true;
+
+	devm_led_classdev_register(&pdev->dev, &tpad_led);
 
 	wmi_input_setup();
 	battery_hook_register(&battery_hook);
@@ -859,9 +869,6 @@ static void acpi_remove(struct platform_device *pdev)
 {
 	sysfs_remove_group(&pf_device->dev.kobj, &dev_attribute_group);
 
-	led_classdev_unregister(&tpad_led);
-	led_classdev_unregister(&kbd_backlight);
-
 	battery_hook_unregister(&battery_hook);
 	wmi_input_destroy();
 	platform_device_unregister(pf_device);
Signature · 1 line
2.53.0
author maintainer
#493 lore raw

PATCH 479/1376 remoteproc: qcom_q6v5_adsp: Fix reference leak for device node

In reply to Greg Kroah-Hartman

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

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

From: Felix Gu <[email protected]>

[ Upstream commit 8c952807c2cebd5e9e9b37146c9383229794c129 ]

When calling of_parse_phandle_with_args(), the caller is responsible to call of_node_put() to release the reference of device node. In adsp_map_carveout, it does not release the reference.

Fixes f22eedff28af ("remoteproc: qcom: Add support for memory sandbox")
---
 drivers/remoteproc/qcom_q6v5_adsp.c | 1 +
 1 file changed, 1 insertion(+)
drivers/remoteproc/qcom_q6v5_adsp.c +1 -0
index 223f6ca0745d3..80ac739621bed 100644
@@ -355,6 +355,7 @@ static int adsp_map_carveout(struct rproc *rproc)
 		return ret;
 
 	sid = args.args[0] & SID_MASK_DEFAULT;
+	of_node_put(args.np);
 
 	/* Add SID configuration for ADSP Firmware to SMMU */
 	iova =  adsp->mem_phys | (sid << 32);
Signature · 1 line
2.53.0
author maintainer
#494 lore raw

PATCH 480/1376 hwspinlock: propagate errno when registering single lock

In reply to Greg Kroah-Hartman

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

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

From: Wolfram Sang <[email protected]>

[ Upstream commit e088ffa9a00eaaaf90da74763e774ca160969c26 ]

hwspin_lock_register_single() always returns 0 despite checking the result from radix_tree_insert(). Propagate the errno to make sanity checks in callers of this function actually meaningful.

Fixes 300bab9770e2 ("hwspinlock/core: register a bank of hwspinlocks in a single API call")
---
 drivers/hwspinlock/hwspinlock_core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwspinlock/hwspinlock_core.c +1 -1
index 6505261e60686..b27a2e33a6117 100644
@@ -472,7 +472,7 @@ static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id)
 
 out:
 	mutex_unlock(&hwspinlock_tree_lock);
-	return 0;
+	return ret;
 }
 
 static struct hwspinlock *hwspin_lock_unregister_single(unsigned int id)
Signature · 1 line
2.53.0
author maintainer
#495 lore raw

PATCH 481/1376 selftests/sched_ext: Fix bpf_link leak on early return in prog_run

In reply to Greg Kroah-Hartman

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

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

From: Liang Luo <[email protected]>

[ Upstream commit e655c1f1bd14804f398df7da029c4a7e3f9ccd7f ]

In prog_run's run(), the bpf_link is attached early but only destroyed on the success path. The three SCX_EQ assertions between attach and destroy expand to a direct 'return SCX_TEST_FAIL', so if any of them triggers, bpf_link__destroy() is never reached and the BPF scheduler stays loaded. All subsequent tests then fail to attach because SCX is not in the DISABLED state.

Convert those assertions to explicit checks that jump to a unified 'out' label which always runs the cleanup, matching the pattern used in cyclic_kick_wait.c.

Fixes a5db7817af78 ("sched_ext: Add selftests")
---
 tools/testing/selftests/sched_ext/prog_run.c | 34 +++++++++++++++-----
 1 file changed, 26 insertions(+), 8 deletions(-)
tools/testing/selftests/sched_ext/prog_run.c +26 -8
index 3cd57ef8daaa5..a75323fe8a2c7 100644
@@ -28,7 +28,8 @@ static enum scx_test_status setup(void **ctx)
 static enum scx_test_status run(void *ctx)
 {
 	struct prog_run *skel = ctx;
-	struct bpf_link *link;
+	struct bpf_link *link = NULL;
+	enum scx_test_status status = SCX_TEST_PASS;
 	int prog_fd, err = 0;
 
 	prog_fd = bpf_program__fd(skel->progs.prog_run_syscall);
@@ -42,23 +43,40 @@ static enum scx_test_status run(void *ctx)
 	link = bpf_map__attach_struct_ops(skel->maps.prog_run_ops);
 	if (!link) {
 		SCX_ERR("Failed to attach scheduler");
-		close(prog_fd);
-		return SCX_TEST_FAIL;
+		status = SCX_TEST_FAIL;
+		goto out;
 	}
 
 	err = bpf_prog_test_run_opts(prog_fd, &topts);
-	SCX_EQ(err, 0);
+	if (err) {
+		SCX_ERR("BPF_PROG_RUN failed (%d)", err);
+		status = SCX_TEST_FAIL;
+		goto out;
+	}
 
 	/* Assumes uei.kind is written last */
 	while (skel->data->uei.kind == EXIT_KIND(SCX_EXIT_NONE))
 		sched_yield();
 
-	SCX_EQ(skel->data->uei.kind, EXIT_KIND(SCX_EXIT_UNREG_BPF));
-	SCX_EQ(skel->data->uei.exit_code, 0xdeadbeef);
+	if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_UNREG_BPF)) {
+		SCX_ERR("Unexpected exit kind: %llu",
+			(unsigned long long)skel->data->uei.kind);
+		status = SCX_TEST_FAIL;
+		goto out;
+	}
+	if (skel->data->uei.exit_code != 0xdeadbeef) {
+		SCX_ERR("Unexpected exit code: %lld",
+			(long long)skel->data->uei.exit_code);
+		status = SCX_TEST_FAIL;
+		goto out;
+	}
+
+out:
 	close(prog_fd);
-	bpf_link__destroy(link);
+	if (link)
+		bpf_link__destroy(link);
 
-	return SCX_TEST_PASS;
+	return status;
 }
 
 static void cleanup(void *ctx)
Signature · 1 line
2.53.0
author maintainer
#496 lore raw

PATCH 482/1376 serial: ma35d1: Fix OF node reference leaks in console init

In reply to Greg Kroah-Hartman

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

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

From: Yuho Choi <[email protected]>

[ Upstream commit 8dfea56f350b3dc826f35711802ad6ae8fae0748 ]

ma35d1serial_console_init_port() stores matching UART device nodes in ma35d1serial_uart_nodes[] with an extra of_node_get() so that console setup can later read the "reg" property. However, the stored references are never released after console setup has finished using them.

Drop the stored node reference after ma35d1serial_console_setup() reads the "reg" property, and clear the array slot to avoid leaving a stale pointer behind. Also release the iterator reference before breaking out of for_each_matching_node(), since the normal iterator advance will not run in that path.

Fixes 930cbf92db01 ("tty: serial: Add Nuvoton ma35d1 serial driver support")
---
 drivers/tty/serial/ma35d1_serial.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/tty/serial/ma35d1_serial.c +10 -2
index 3b4206e815fe9..2c1c8d7480230 100644
@@ -608,8 +608,14 @@ static int __init ma35d1serial_console_setup(struct console *co, char *options)
 	if (!np || !p)
 		return -ENODEV;
 
-	if (of_property_read_u32_array(np, "reg", val32, ARRAY_SIZE(val32)) != 0)
+	if (of_property_read_u32_array(np, "reg", val32, ARRAY_SIZE(val32)) != 0) {
+		of_node_put(np);
+		ma35d1serial_uart_nodes[co->index] = NULL;
 		return -EINVAL;
+	}
+
+	of_node_put(np);
+	ma35d1serial_uart_nodes[co->index] = NULL;
 
 	p->port.iobase = val32[1];
 	p->port.membase = ioremap(p->port.iobase, MA35_UART_REG_SIZE);
@@ -648,8 +654,10 @@ static void ma35d1serial_console_init_port(void)
 			of_node_get(np);
 			ma35d1serial_uart_nodes[i] = np;
 			i++;
-			if (i == MA35_UART_NR)
+			if (i == MA35_UART_NR) {
+				of_node_put(np);
 				break;
+			}
 		}
 	}
 }
Signature · 1 line
2.53.0
author maintainer
#497 lore raw

PATCH 483/1376 serial: qcom-geni: do not advance stale DMA completions

In reply to Greg Kroah-Hartman

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

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

From: Guangshuo Li <[email protected]>

[ Upstream commit 7ea38c49e7178960926657863299face6dc0e1b0 ]

The qcom GENI serial DMA TX completion path advances the transmit fifo by the number of bytes recorded in port->tx_remaining.

If uart_flush_buffer() runs after the hardware has completed a DMA transfer but before the DMA completion interrupt has been handled, the serial core resets the transmit fifo while port->tx_remaining still describes the old DMA transfer.

A previous fix avoided advancing an empty fifo by checking that the fifo length is at least tx_remaining. That still does not distinguish the old DMA payload from new bytes written after the flush. If userspace writes new data before the stale DMA completion interrupt is handled, the fifo can again contain at least tx_remaining bytes and the stale completion can advance and discard those new bytes.

Mark an in-flight DMA transfer stale when the transmit fifo is flushed. The later completion still unprepares the original DMA mapping using the saved length, but it no longer advances the transmit fifo.

Fixes 2aaa43c70778 ("tty: serial: qcom-geni-serial: add support for serial engine DMA")
---
 drivers/tty/serial/qcom_geni_serial.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/tty/serial/qcom_geni_serial.c +9 -1
index 6e5b31ebd5d64..0cccc26e932b2 100644
@@ -132,6 +132,7 @@ struct qcom_geni_serial_port {
 
 	unsigned int tx_remaining;
 	unsigned int tx_queued;
+	bool tx_dma_stale;
 	int wakeup_irq;
 	bool rx_tx_swap;
 	bool cts_rts_swap;
@@ -659,6 +660,7 @@ static void qcom_geni_serial_start_tx_dma(struct uart_port *uport)
 	}
 
 	port->tx_remaining = xmit_size;
+	port->tx_dma_stale = false;
 }
 
 static void qcom_geni_serial_start_tx_fifo(struct uart_port *uport)
@@ -991,6 +993,7 @@ static void qcom_geni_serial_handle_tx_dma(struct uart_port *uport)
 	struct qcom_geni_serial_port *port = to_dev_port(uport);
 	struct tty_port *tport = &uport->state->port;
 	unsigned int fifo_len = kfifo_len(&tport->xmit_fifo);
+	bool tx_dma_stale = port->tx_dma_stale;
 
 	/*
 	 * Only advance the kfifo if it still contains the bytes that were
@@ -1001,12 +1004,13 @@ static void qcom_geni_serial_handle_tx_dma(struct uart_port *uport)
 	 * kfifo->in, making kfifo_len() wrap to UART_XMIT_SIZE - tx_remaining
 	 * and triggering a spurious large DMA transfer of stale data.
 	 */
-	if (fifo_len >= port->tx_remaining)
+	if (!tx_dma_stale && fifo_len >= port->tx_remaining)
 		uart_xmit_advance(uport, port->tx_remaining);
 
 	geni_se_tx_dma_unprep(&port->se, port->tx_dma_addr, port->tx_remaining);
 	port->tx_dma_addr = 0;
 	port->tx_remaining = 0;
+	port->tx_dma_stale = false;
 
 	if (!kfifo_is_empty(&tport->xmit_fifo))
 		qcom_geni_serial_start_tx_dma(uport);
@@ -1142,6 +1146,10 @@ static void qcom_geni_serial_shutdown(struct uart_port *uport)
 
 static void qcom_geni_serial_flush_buffer_fifo(struct uart_port *uport)
 {
+	struct qcom_geni_serial_port *port = to_dev_port(uport);
+
+	if (port->tx_dma_addr)
+		port->tx_dma_stale = true;
 	qcom_geni_serial_cancel_tx_cmd(uport);
 }
 
Signature · 1 line
2.53.0
author maintainer
#498 lore raw

PATCH 484/1376 usb: gadget: f_fs: Fix fence cleanup in ffs_dmabuf_transfer() error paths

In reply to Greg Kroah-Hartman

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

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

From: Nuno Sá <[email protected]>

[ Upstream commit 621707dc67c9846fd876d7579ec951d92aa033f1 ]

The error paths for endpoint-disabled (ESHUTDOWN) and request-allocation failure (ENOMEM) in ffs_dmabuf_transfer() jump to err_fence_put which calls dma_fence_put() on the fence. However, at that point the fence has only been kmalloc'd — dma_fence_init() has not been called yet, so the refcount and the fence ops are uninitialized. Calling dma_fence_put() on such an object leads to undefined behavior.

Use kfree() instead, since the fence is just a plain allocation at this stage, and rename the label to err_fence_free to reflect the actual cleanup action.

Fixes 7b07a2a7ca02 ("usb: gadget: functionfs: Add DMABUF import interface")
---
 drivers/usb/gadget/function/f_fs.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/usb/gadget/function/f_fs.c +4 -4
index cbed66a528269..24bfde82c385b 100644
@@ -1678,13 +1678,13 @@ static int ffs_dmabuf_transfer(struct file *file,
 	/* In the meantime, endpoint got disabled or changed. */
 	if (epfile->ep != ep) {
 		ret = -ESHUTDOWN;
-		goto err_fence_put;
+		goto err_fence_free;
 	}
 
 	usb_req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC);
 	if (!usb_req) {
 		ret = -ENOMEM;
-		goto err_fence_put;
+		goto err_fence_free;
 	}
 
 	/*
@@ -1733,9 +1733,9 @@ static int ffs_dmabuf_transfer(struct file *file,
 
 	return ret;
 
-err_fence_put:
+err_fence_free:
 	spin_unlock_irq(&epfile->ffs->eps_lock);
-	dma_fence_put(&fence->base);
+	kfree(fence);
 err_resv_unlock:
 	dma_resv_unlock(dmabuf->resv);
 err_attachment_put:
Signature · 1 line
2.53.0
author maintainer
#499 lore raw

PATCH 485/1376 usb: gadget: configfs: fix out-of-bounds read of qw_sign

In reply to Greg Kroah-Hartman

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

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

From: Michael Bommarito <[email protected]>

[ Upstream commit f63edb54d8f738f9c21e2068c777ae1c097df6b7 ]

os_desc_qw_sign_show() passes OS_STRING_QW_SIGN_LEN as the input length to utf16s_to_utf8s(), but that argument counts UTF-16 code units while OS_STRING_QW_SIGN_LEN (14) is the byte size of qw_sign[]. The array holds only OS_STRING_QW_SIGN_LEN / 2 (7) code units, so the conversion reads up to 7 units (14 bytes) past the end of qw_sign[] into the following members of struct gadget_info when the stored signature fills the array without a NUL terminator, exposing those bytes through the configfs attribute.

The store path halves the count for its input bound but passes the full byte count as the utf8s_to_utf16s() output limit; use the destination code-unit count in both directions.

Fixes 76180d716f91 ("usb: gadget: configfs: make qw_sign attribute symmetric")
Assisted-by Claude:claude-opus-4-8
---
 drivers/usb/gadget/configfs.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/usb/gadget/configfs.c +2 -2
index 82282373c786b..6b3713066ac65 100644
@@ -1177,7 +1177,7 @@ static ssize_t os_desc_qw_sign_show(struct config_item *item, char *page)
 	struct gadget_info *gi = os_desc_item_to_gadget_info(item);
 	int res;
 
-	res = utf16s_to_utf8s((wchar_t *) gi->qw_sign, OS_STRING_QW_SIGN_LEN,
+	res = utf16s_to_utf8s((wchar_t *) gi->qw_sign, OS_STRING_QW_SIGN_LEN / 2,
 			      UTF16_LITTLE_ENDIAN, page, PAGE_SIZE - 1);
 	page[res++] = '\n';
 
@@ -1199,7 +1199,7 @@ static ssize_t os_desc_qw_sign_store(struct config_item *item, const char *page,
 	mutex_lock(&gi->lock);
 	res = utf8s_to_utf16s(page, l,
 			      UTF16_LITTLE_ENDIAN, (wchar_t *) gi->qw_sign,
-			      OS_STRING_QW_SIGN_LEN);
+			      OS_STRING_QW_SIGN_LEN / 2);
 	if (res > 0)
 		res = len;
 	mutex_unlock(&gi->lock);
Signature · 1 line
2.53.0
author maintainer
#500 lore raw

PATCH 486/1376 usb: ljca: bound bank_num in ljca_enumerate_gpio()

In reply to Greg Kroah-Hartman

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

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

From: Maoyi Xie <[email protected]>

[ Upstream commit dd9483726d0f16c1a56879c3edb65128259a4e2b ]

ljca_enumerate_gpio() reads desc->bank_num from the device and loops valid_pin[i] = get_unaligned_le32(...) for i < bank_num. valid_pin[] holds only LJCA_MAX_GPIO_NUM / 32 = 2 entries.

Two checks run before the loop. The reply length must match struct_size(desc, bank_desc, bank_num). The product pins_per_bank * bank_num must not exceed LJCA_MAX_GPIO_NUM. Neither one bounds bank_num against the size of valid_pin[]. The reply is capped at LJCA_MAX_PAYLOAD_SIZE (60) bytes, so the struct_size check limits bank_num to 9. A device that reports bank_num 9 with pins_per_bank 7 still passes both checks. gpio_num is 63 and the reply is 56 bytes. The loop then writes nine u32 into the two entry array and overruns valid_pin[] on the stack.

A broken or malicious LJCA device can therefore overflow the stack. Reject a bank_num that does not fit valid_pin[].

---
 drivers/usb/misc/usb-ljca.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/usb/misc/usb-ljca.c +3 -0
index d9c21f7830557..e6e3888451fa2 100644
@@ -585,6 +585,9 @@ static int ljca_enumerate_gpio(struct ljca_adapter *adap)
 	if (gpio_num > LJCA_MAX_GPIO_NUM)
 		return -EINVAL;
 
+	if (desc->bank_num > ARRAY_SIZE(valid_pin))
+		return -EINVAL;
+
 	/* construct platform data */
 	gpio_info = kzalloc(sizeof *gpio_info, GFP_KERNEL);
 	if (!gpio_info)
Signature · 1 line
2.53.0
author maintainer
#501 lore raw

PATCH 487/1376 usb: gadget: aspeed_udc: check endpoint DMA allocation

In reply to Greg Kroah-Hartman

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

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

From: Ruoyu Wang <[email protected]>

[ Upstream commit 97cee53a94be3bd4fd8fbed6071bd2f32dad1ab1 ]

ast_udc_probe() allocates a coherent DMA buffer used as the backing store for endpoint buffers. ast_udc_init_ep() derives per-endpoint buffer pointers from udc->ep0_buf, so a failed allocation is dereferenced during probe.

Check the allocation before endpoint setup. The existing probe error path called ast_udc_remove(), which unregisters the gadget unconditionally and is not safe before usb_add_gadget_udc() succeeds. Add a local cleanup helper for probe failures so pre-registration failures only unwind the resources that were actually initialized.

This was found by a local static analysis checker for unchecked allocator returns while scanning Linux 6.16. The change was checked by applying it to current mainline and by running checkpatch. I do not have access to Aspeed UDC hardware, so no runtime testing was performed.

---
 drivers/usb/gadget/udc/aspeed_udc.c | 50 ++++++++++++++++++-----------
 1 file changed, 32 insertions(+), 18 deletions(-)
drivers/usb/gadget/udc/aspeed_udc.c +32 -18
index f4781e611aaa2..efcceb886bb40 100644
@@ -1434,25 +1434,12 @@ static void ast_udc_init_hw(struct ast_udc_dev *udc)
 	ast_udc_write(udc, 0, AST_UDC_EP0_CTRL);
 }
 
-static void ast_udc_remove(struct platform_device *pdev)
+static void ast_udc_cleanup(struct platform_device *pdev)
 {
 	struct ast_udc_dev *udc = platform_get_drvdata(pdev);
 	unsigned long flags;
 	u32 ctrl;
 
-	usb_del_gadget_udc(&udc->gadget);
-	if (udc->driver) {
-		/*
-		 * This is broken as only some cleanup is skipped, *udev is
-		 * freed and the register mapping goes away. Any further usage
-		 * probably crashes. Also the device is unbound, so the skipped
-		 * cleanup is never catched up later.
-		 */
-		dev_alert(&pdev->dev,
-			  "Driver is busy and still going away. Fasten your seat belts!\n");
-		return;
-	}
-
 	spin_lock_irqsave(&udc->lock, flags);
 
 	/* Disable upstream port connection */
@@ -1472,6 +1459,26 @@ static void ast_udc_remove(struct platform_device *pdev)
 	udc->ep0_buf = NULL;
 }
 
+static void ast_udc_remove(struct platform_device *pdev)
+{
+	struct ast_udc_dev *udc = platform_get_drvdata(pdev);
+
+	usb_del_gadget_udc(&udc->gadget);
+	if (udc->driver) {
+		/*
+		 * This is broken as only some cleanup is skipped, *udev is
+		 * freed and the register mapping goes away. Any further usage
+		 * probably crashes. Also the device is unbound, so the skipped
+		 * cleanup is never catched up later.
+		 */
+		dev_alert(&pdev->dev,
+			  "Driver is busy and still going away. Fasten your seat belts!\n");
+		return;
+	}
+
+	ast_udc_cleanup(pdev);
+}
+
 static int ast_udc_probe(struct platform_device *pdev)
 {
 	enum usb_device_speed max_speed;
@@ -1524,6 +1531,12 @@ static int ast_udc_probe(struct platform_device *pdev)
 					  AST_UDC_NUM_ENDPOINTS,
 					  &udc->ep0_buf_dma, GFP_KERNEL);
 
+	if (!udc->ep0_buf) {
+		clk_disable_unprepare(udc->clk);
+		rc = -ENOMEM;
+		goto err;
+	}
+
 	udc->gadget.speed = USB_SPEED_UNKNOWN;
 	udc->gadget.max_speed = USB_SPEED_HIGH;
 	udc->creq = udc->reg + AST_UDC_SETUP0;
@@ -1553,20 +1566,20 @@ static int ast_udc_probe(struct platform_device *pdev)
 	udc->irq = platform_get_irq(pdev, 0);
 	if (udc->irq < 0) {
 		rc = udc->irq;
-		goto err;
+		goto err_cleanup;
 	}
 
 	rc = devm_request_irq(&pdev->dev, udc->irq, ast_udc_isr, 0,
 			      KBUILD_MODNAME, udc);
 	if (rc) {
 		dev_err(&pdev->dev, "Failed to request interrupt\n");
-		goto err;
+		goto err_cleanup;
 	}
 
 	rc = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
 	if (rc) {
 		dev_err(&pdev->dev, "Failed to add gadget udc\n");
-		goto err;
+		goto err_cleanup;
 	}
 
 	dev_info(&pdev->dev, "Initialized udc in USB%s mode\n",
@@ -1574,9 +1587,10 @@ static int ast_udc_probe(struct platform_device *pdev)
 
 	return 0;
 
+err_cleanup:
+	ast_udc_cleanup(pdev);
 err:
 	dev_err(&pdev->dev, "Failed to udc probe, rc:0x%x\n", rc);
-	ast_udc_remove(pdev);
 
 	return rc;
 }
Signature · 1 line
2.53.0
author maintainer
#502 lore raw

PATCH 488/1376 USB: make single lock for all usb dynamic id lists

In reply to Greg Kroah-Hartman

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

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

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

[ Upstream commit 0b3144da31f855fce652303f588416a60991bdef ]

There are a number of places where we accidentally pass in a constant structure to later cast it off to a dynamic one, and then attempt to grab a lock on it, which is not a good idea. To help resolve this, move the dynamic id lock out of the dynamic id structure for the driver and into one single lock for all USB dynamic ids. As this lock should never have any real contention (it's only every accessed when a device is added or removed, which is always serialized) there should not be any difference except for some memory savings.

Note, this just converts the existing use of the dynamic id lock to the new static lock, there is one place that is accessing the dynamic id list without grabbing the lock, that will be fixed up in a follow-on change.

Stable-dep-of: ef8154d8b52d ("usb: fix UAF when probe runs concurrent to dyn ID removal")

---
 drivers/usb/common/common.c     |  3 +++
 drivers/usb/core/driver.c       | 15 +++++----------
 drivers/usb/serial/bus.c        |  4 +---
 drivers/usb/serial/usb-serial.c |  4 +---
 include/linux/usb.h             |  2 +-
 5 files changed, 11 insertions(+), 17 deletions(-)
drivers/usb/common/common.c +3 -0
index b7bea1015d7c1..871cf199b6bf1 100644
@@ -415,6 +415,9 @@ EXPORT_SYMBOL_GPL(usb_of_get_companion_dev);
 struct dentry *usb_debug_root;
 EXPORT_SYMBOL_GPL(usb_debug_root);
 
+DEFINE_MUTEX(usb_dynids_lock);
+EXPORT_SYMBOL_GPL(usb_dynids_lock);
+
 static int __init usb_common_init(void)
 {
 	usb_debug_root = debugfs_create_dir("usb", NULL);
drivers/usb/core/driver.c +5 -10
index 0c3f12daac79e..bc3c00580238d 100644
@@ -95,9 +95,9 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
 		}
 	}
 
-	spin_lock(&dynids->lock);
+	mutex_lock(&usb_dynids_lock);
 	list_add_tail(&dynid->node, &dynids->list);
-	spin_unlock(&dynids->lock);
+	mutex_unlock(&usb_dynids_lock);
 
 	retval = driver_attach(driver);
 
@@ -160,7 +160,7 @@ static ssize_t remove_id_store(struct device_driver *driver, const char *buf,
 	if (fields < 2)
 		return -EINVAL;
 
-	spin_lock(&usb_driver->dynids.lock);
+	guard(mutex)(&usb_dynids_lock);
 	list_for_each_entry_safe(dynid, n, &usb_driver->dynids.list, node) {
 		struct usb_device_id *id = &dynid->id;
 
@@ -171,7 +171,6 @@ static ssize_t remove_id_store(struct device_driver *driver, const char *buf,
 			break;
 		}
 	}
-	spin_unlock(&usb_driver->dynids.lock);
 	return count;
 }
 
@@ -220,12 +219,11 @@ static void usb_free_dynids(struct usb_driver *usb_drv)
 {
 	struct usb_dynid *dynid, *n;
 
-	spin_lock(&usb_drv->dynids.lock);
+	guard(mutex)(&usb_dynids_lock);
 	list_for_each_entry_safe(dynid, n, &usb_drv->dynids.list, node) {
 		list_del(&dynid->node);
 		kfree(dynid);
 	}
-	spin_unlock(&usb_drv->dynids.lock);
 }
 
 static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *intf,
@@ -233,14 +231,12 @@ static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *in
 {
 	struct usb_dynid *dynid;
 
-	spin_lock(&drv->dynids.lock);
+	guard(mutex)(&usb_dynids_lock);
 	list_for_each_entry(dynid, &drv->dynids.list, node) {
 		if (usb_match_one_id(intf, &dynid->id)) {
-			spin_unlock(&drv->dynids.lock);
 			return &dynid->id;
 		}
 	}
-	spin_unlock(&drv->dynids.lock);
 	return NULL;
 }
 
@@ -1076,7 +1072,6 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
 	new_driver->driver.owner = owner;
 	new_driver->driver.mod_name = mod_name;
 	new_driver->driver.dev_groups = new_driver->dev_groups;
-	spin_lock_init(&new_driver->dynids.lock);
 	INIT_LIST_HEAD(&new_driver->dynids.list);
 
 	retval = driver_register(&new_driver->driver);
drivers/usb/serial/bus.c +1 -3
index d200e2c29a8ff..2fea1b1db4a26 100644
@@ -136,12 +136,11 @@ static void free_dynids(struct usb_serial_driver *drv)
 {
 	struct usb_dynid *dynid, *n;
 
-	spin_lock(&drv->dynids.lock);
+	guard(mutex)(&usb_dynids_lock);
 	list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
 		list_del(&dynid->node);
 		kfree(dynid);
 	}
-	spin_unlock(&drv->dynids.lock);
 }
 
 const struct bus_type usb_serial_bus_type = {
@@ -157,7 +156,6 @@ int usb_serial_bus_register(struct usb_serial_driver *driver)
 	int retval;
 
 	driver->driver.bus = &usb_serial_bus_type;
-	spin_lock_init(&driver->dynids.lock);
 	INIT_LIST_HEAD(&driver->dynids.list);
 
 	retval = driver_register(&driver->driver);
drivers/usb/serial/usb-serial.c +1 -3
index 2ee0b64b8be0a..c78ff40b1e5f8 100644
@@ -706,14 +706,12 @@ static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
 {
 	struct usb_dynid *dynid;
 
-	spin_lock(&drv->dynids.lock);
+	guard(mutex)(&usb_dynids_lock);
 	list_for_each_entry(dynid, &drv->dynids.list, node) {
 		if (usb_match_one_id(intf, &dynid->id)) {
-			spin_unlock(&drv->dynids.lock);
 			return &dynid->id;
 		}
 	}
-	spin_unlock(&drv->dynids.lock);
 	return NULL;
 }
 
include/linux/usb.h +1 -1
index 049b012638bea..06eb0a62895d3 100644
@@ -1132,8 +1132,8 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size)
 /* ----------------------------------------------------------------------- */
 
 /* Stuff for dynamic usb ids */
+extern struct mutex usb_dynids_lock;
 struct usb_dynids {
-	spinlock_t lock;
 	struct list_head list;
 };
 
Signature · 1 line
2.53.0
author maintainer
#503 lore raw

PATCH 489/1376 USB: make to_usb_driver() use container_of_const()

In reply to Greg Kroah-Hartman

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

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

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

[ Upstream commit 2f3aab7aecb827ba93c6222646eb0faa8228d590 ]

Turns out that we have some const pointers being passed to to_usb_driver() but were not catching this. Change the macro to properly propagate the const-ness of the pointer so that we will notice when we try to write to memory that we shouldn't be writing to.

This requires fixing up the usb_match_dynamic_id() function as well, because it can handle a const * to struct usb_driver.

Stable-dep-of: ef8154d8b52d ("usb: fix UAF when probe runs concurrent to dyn ID removal")

---
 drivers/usb/core/driver.c | 4 ++--
 include/linux/usb.h       | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)
drivers/usb/core/driver.c +2 -2
index bc3c00580238d..f0f13554709e0 100644
@@ -227,7 +227,7 @@ static void usb_free_dynids(struct usb_driver *usb_drv)
 }
 
 static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *intf,
-							struct usb_driver *drv)
+							const struct usb_driver *drv)
 {
 	struct usb_dynid *dynid;
 
@@ -889,7 +889,7 @@ static int usb_device_match(struct device *dev, const struct device_driver *drv)
 
 	} else if (is_usb_interface(dev)) {
 		struct usb_interface *intf;
-		struct usb_driver *usb_drv;
+		const struct usb_driver *usb_drv;
 		const struct usb_device_id *id;
 
 		/* device drivers never match interfaces */
include/linux/usb.h +1 -1
index 06eb0a62895d3..2004a2db81ced 100644
@@ -1246,7 +1246,7 @@ struct usb_driver {
 	unsigned int disable_hub_initiated_lpm:1;
 	unsigned int soft_unbind:1;
 };
-#define	to_usb_driver(d) container_of(d, struct usb_driver, driver)
+#define	to_usb_driver(d) container_of_const(d, struct usb_driver, driver)
 
 /**
  * struct usb_device_driver - identifies USB device driver to usbcore
Signature · 1 line
2.53.0
author maintainer
#504 lore raw

PATCH 490/1376 usb: fix UAF when probe runs concurrent to dyn ID removal

In reply to Greg Kroah-Hartman

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

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

From: Gary Guo <[email protected]>

[ Upstream commit ef8154d8b52d60338c1fd8d793cd8e891c604c14 ]

Dynamic IDs are only guaranteed to be valid when usb_dynids_lock is held, as remove_id_store can free the node. Thus, make a copy in usb_probe_interface. Clarify the documentation that the id parameter is only valid during the probe.

USB serial has the same pattern, but it does not need fixing as the IDs cannot be removed via sysfs.

Fixes 0c7a2b72746a ("USB: add remove_id sysfs attr for usb drivers")
---
 drivers/usb/core/driver.c | 12 ++++++++----
 include/linux/usb.h       |  3 ++-
 2 files changed, 10 insertions(+), 5 deletions(-)
drivers/usb/core/driver.c +8 -4
index f0f13554709e0..528274e3cd7ad 100644
@@ -227,14 +227,16 @@ static void usb_free_dynids(struct usb_driver *usb_drv)
 }
 
 static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *intf,
-							const struct usb_driver *drv)
+							const struct usb_driver *drv,
+							struct usb_device_id *id_copy)
 {
 	struct usb_dynid *dynid;
 
 	guard(mutex)(&usb_dynids_lock);
 	list_for_each_entry(dynid, &drv->dynids.list, node) {
 		if (usb_match_one_id(intf, &dynid->id)) {
-			return &dynid->id;
+			*id_copy = dynid->id;
+			return id_copy;
 		}
 	}
 	return NULL;
@@ -320,6 +322,7 @@ static int usb_probe_interface(struct device *dev)
 	struct usb_interface *intf = to_usb_interface(dev);
 	struct usb_device *udev = interface_to_usbdev(intf);
 	const struct usb_device_id *id;
+	struct usb_device_id id_copy;
 	int error = -ENODEV;
 	int lpm_disable_error = -ENODEV;
 
@@ -339,7 +342,7 @@ static int usb_probe_interface(struct device *dev)
 		return error;
 	}
 
-	id = usb_match_dynamic_id(intf, driver);
+	id = usb_match_dynamic_id(intf, driver, &id_copy);
 	if (!id)
 		id = usb_match_id(intf, driver->id_table);
 	if (!id)
@@ -891,6 +894,7 @@ static int usb_device_match(struct device *dev, const struct device_driver *drv)
 		struct usb_interface *intf;
 		const struct usb_driver *usb_drv;
 		const struct usb_device_id *id;
+		struct usb_device_id id_copy;
 
 		/* device drivers never match interfaces */
 		if (is_usb_device_driver(drv))
@@ -903,7 +907,7 @@ static int usb_device_match(struct device *dev, const struct device_driver *drv)
 		if (id)
 			return 1;
 
-		id = usb_match_dynamic_id(intf, usb_drv);
+		id = usb_match_dynamic_id(intf, usb_drv, &id_copy);
 		if (id)
 			return 1;
 	}
include/linux/usb.h +2 -1
index 2004a2db81ced..0012259ac910c 100644
@@ -1159,7 +1159,8 @@ extern ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf);
  *	interface.  It may also use usb_set_interface() to specify the
  *	appropriate altsetting.  If unwilling to manage the interface,
  *	return -ENODEV, if genuine IO errors occurred, an appropriate
- *	negative errno value.
+ *	negative errno value.  The usb_device_id parameter is only valid during
+ *	probe.
  * @disconnect: Called when the interface is no longer accessible, usually
  *	because its device has been (or is being) disconnected or the
  *	driver module is being unloaded.
Signature · 1 line
2.53.0
#505 lore raw

Re: [PATCH 6.12 0490/1376] usb: fix UAF when probe runs concurrent to dyn ID removal

Hi Greg/Sasha,

Quoted 38 lines · Greg Kroah-Hartman

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

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

From: Gary Guo <[email protected]>

[ Upstream commit ef8154d8b52d60338c1fd8d793cd8e891c604c14 ]

Dynamic IDs are only guaranteed to be valid when usb_dynids_lock is held, as remove_id_store can free the node. Thus, make a copy in usb_probe_interface. Clarify the documentation that the id parameter is only valid during the probe.

USB serial has the same pattern, but it does not need fixing as the IDs cannot be removed via sysfs.

Fixes 0c7a2b72746a ("USB: add remove_id sysfs attr for usb drivers")
---
  drivers/usb/core/driver.c | 12 ++++++++----
  include/linux/usb.h       |  3 ++-
  2 files changed, 10 insertions(+), 5 deletions(-)
drivers/usb/core/driver.c +2 -1
index f0f13554709e0..528274e3cd7ad 100644
@@ -227,14 +227,16 @@ static void usb_free_dynids(struct usb_driver *usb_drv)
  }
 
  static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *intf,
-							const struct usb_driver *drv)
+							const struct usb_driver *drv,
+							struct usb_device_id *id_copy)

drivers/usb/core/driver.c static void usb_free_dynids(struct usb_driver *usb_drv) · line 240

Quoted 10 lines
drivers/usb/core/driver.c +2 -1
  {
  	struct usb_dynid *dynid;
 
  	guard(mutex)(&usb_dynids_lock);
  	list_for_each_entry(dynid, &drv->dynids.list, node) {
  		if (usb_match_one_id(intf, &dynid->id)) {
-			return &dynid->id;
+			*id_copy = dynid->id;
+			return id_copy;
  		}

I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.

The core UAF fix is present, but it deliberately passes a local copy of a dynamic USB ID to probe. The 6.12 xusbatm driver still computes id - xusbatm_usb_ids and uses that as an array index. A copied dynamic ID is not an element of that static array, so this driver violates the new contract.

Upstream prerequisite code:

    int drv_ix = id->driver_info;
    .no_dynamic_id = 1,

Downstream 6.12.y code:

int drv_ix = id - xusbatm_usb_ids;
xusbatm_drivers + (id - xusbatm_usb_ids)

Upstream first applied eb6cd6d3d8ab, "usb: xusbatm: don't rely on id table pointer arithmetic".

Maybe we should queue that prerequisite as well. Thoughts?

thanks,
Harshit> }

Quoted 49 lines
drivers/usb/core/driver.c +4 -2
  	return NULL;
@@ -320,6 +322,7 @@ static int usb_probe_interface(struct device *dev)
  	struct usb_interface *intf = to_usb_interface(dev);
  	struct usb_device *udev = interface_to_usbdev(intf);
  	const struct usb_device_id *id;
+	struct usb_device_id id_copy;
  	int error = -ENODEV;
  	int lpm_disable_error = -ENODEV;
 
@@ -339,7 +342,7 @@ static int usb_probe_interface(struct device *dev)
  		return error;
  	}
 
-	id = usb_match_dynamic_id(intf, driver);
+	id = usb_match_dynamic_id(intf, driver, &id_copy);
  	if (!id)
  		id = usb_match_id(intf, driver->id_table);
  	if (!id)
@@ -891,6 +894,7 @@ static int usb_device_match(struct device *dev, const struct device_driver *drv)
  		struct usb_interface *intf;
  		const struct usb_driver *usb_drv;
  		const struct usb_device_id *id;
+		struct usb_device_id id_copy;
 
  		/* device drivers never match interfaces */
  		if (is_usb_device_driver(drv))
@@ -903,7 +907,7 @@ static int usb_device_match(struct device *dev, const struct device_driver *drv)
  		if (id)
  			return 1;
 
-		id = usb_match_dynamic_id(intf, usb_drv);
+		id = usb_match_dynamic_id(intf, usb_drv, &id_copy);
  		if (id)
  			return 1;
  	}
include/linux/usb.h +2 -1
index 2004a2db81ced..0012259ac910c 100644
@@ -1159,7 +1159,8 @@ extern ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf);
   *	interface.  It may also use usb_set_interface() to specify the
   *	appropriate altsetting.  If unwilling to manage the interface,
   *	return -ENODEV, if genuine IO errors occurred, an appropriate
- *	negative errno value.
+ *	negative errno value.  The usb_device_id parameter is only valid during
+ *	probe.
   * @disconnect: Called when the interface is no longer accessible, usually
   *	because its device has been (or is being) disconnected or the
   *	driver module is being unloaded.
#506 lore raw

Re: [PATCH 6.12 0490/1376] usb: fix UAF when probe runs concurrent to dyn ID removal

Quoted 56 lines · Harshit Mogalapalli

Hi Greg/Sasha,

Quoted 38 lines · Greg Kroah-Hartman

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

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

From: Gary Guo <[email protected]>

[ Upstream commit ef8154d8b52d60338c1fd8d793cd8e891c604c14 ]

Dynamic IDs are only guaranteed to be valid when usb_dynids_lock is held, as remove_id_store can free the node. Thus, make a copy in usb_probe_interface. Clarify the documentation that the id parameter is only valid during the probe.

USB serial has the same pattern, but it does not need fixing as the IDs cannot be removed via sysfs.

Fixes 0c7a2b72746a ("USB: add remove_id sysfs attr for usb drivers")
---
  drivers/usb/core/driver.c | 12 ++++++++----
  include/linux/usb.h       |  3 ++-
  2 files changed, 10 insertions(+), 5 deletions(-)
drivers/usb/core/driver.c +2 -1
index f0f13554709e0..528274e3cd7ad 100644
@@ -227,14 +227,16 @@ static void usb_free_dynids(struct usb_driver *usb_drv)
  }
 
  static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *intf,
-							const struct usb_driver *drv)
+							const struct usb_driver *drv,
+							struct usb_device_id *id_copy)

drivers/usb/core/driver.c static void usb_free_dynids(struct usb_driver *usb_drv) · line 240

Quoted 10 lines
drivers/usb/core/driver.c +2 -1
  {
  	struct usb_dynid *dynid;
 
  	guard(mutex)(&usb_dynids_lock);
  	list_for_each_entry(dynid, &drv->dynids.list, node) {
  		if (usb_match_one_id(intf, &dynid->id)) {
-			return &dynid->id;
+			*id_copy = dynid->id;
+			return id_copy;
  		}

I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.

Quoted 5 lines

The core UAF fix is present, but it deliberately passes a local copy of a dynamic USB ID to probe. The 6.12 xusbatm driver still computes id - xusbatm_usb_ids and uses that as an array index. A copied dynamic ID is not an element of that static array, so this driver violates the new contract.

I fixed all the drivers first before the core fix, but they're no real dependency between them.

Those code that do arithmetic or otherwise use the ID pointer assuming they're static are already broken when the ID pointer is actually from dynamic ID. The stack copy doesn't change it. Correct code stays correct, broken code stays broken.

I think it'd be good if the other patches in that series are backported too -- but that shouldn't be dependency of the core fix.

Best,
Gary

Quoted 67 lines

Upstream prerequisite code:

     int drv_ix = id->driver_info;
     .no_dynamic_id = 1,

Downstream 6.12.y code:

int drv_ix = id - xusbatm_usb_ids;
xusbatm_drivers + (id - xusbatm_usb_ids)

Upstream first applied eb6cd6d3d8ab, "usb: xusbatm: don't rely on id table pointer arithmetic".

Maybe we should queue that prerequisite as well. Thoughts?

thanks,
Harshit> }

Quoted 49 lines
drivers/usb/core/driver.c +4 -2
  	return NULL;
@@ -320,6 +322,7 @@ static int usb_probe_interface(struct device *dev)
  	struct usb_interface *intf = to_usb_interface(dev);
  	struct usb_device *udev = interface_to_usbdev(intf);
  	const struct usb_device_id *id;
+	struct usb_device_id id_copy;
  	int error = -ENODEV;
  	int lpm_disable_error = -ENODEV;
 
@@ -339,7 +342,7 @@ static int usb_probe_interface(struct device *dev)
  		return error;
  	}
 
-	id = usb_match_dynamic_id(intf, driver);
+	id = usb_match_dynamic_id(intf, driver, &id_copy);
  	if (!id)
  		id = usb_match_id(intf, driver->id_table);
  	if (!id)
@@ -891,6 +894,7 @@ static int usb_device_match(struct device *dev, const struct device_driver *drv)
  		struct usb_interface *intf;
  		const struct usb_driver *usb_drv;
  		const struct usb_device_id *id;
+		struct usb_device_id id_copy;
 
  		/* device drivers never match interfaces */
  		if (is_usb_device_driver(drv))
@@ -903,7 +907,7 @@ static int usb_device_match(struct device *dev, const struct device_driver *drv)
  		if (id)
  			return 1;
 
-		id = usb_match_dynamic_id(intf, usb_drv);
+		id = usb_match_dynamic_id(intf, usb_drv, &id_copy);
  		if (id)
  			return 1;
  	}
include/linux/usb.h +2 -1
index 2004a2db81ced..0012259ac910c 100644
@@ -1159,7 +1159,8 @@ extern ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf);
   *	interface.  It may also use usb_set_interface() to specify the
   *	appropriate altsetting.  If unwilling to manage the interface,
   *	return -ENODEV, if genuine IO errors occurred, an appropriate
- *	negative errno value.
+ *	negative errno value.  The usb_device_id parameter is only valid during
+ *	probe.
   * @disconnect: Called when the interface is no longer accessible, usually
   *	because its device has been (or is being) disconnected or the
   *	driver module is being unloaded.
maintainer Applied
#507 lore raw

Re: [PATCH 6.12 0490/1376] usb: fix UAF when probe runs concurrent to dyn ID removal

Quoted 2 lines

I think it'd be good if the other patches in that series are backported too -- but that shouldn't be dependency of the core fix.

Queued for 7.2, 6.18, 6.12, 6.6 and 6.1, thanks.

One exception: 934e1322f18c ("usb: serial: spcp8x5: don't store usb_device_id") is skipped on 6.1, where usb-serial never exposes remove_id and re-derives the id itself, so the stored pointer cannot dangle there.

Signature · 2 lines
Thanks,
Sasha
author maintainer
#508 lore raw

PATCH 491/1376 platform/mellanox: mlxbf-pmc: Check ACPI_COMPANION() against NULL

In reply to Greg Kroah-Hartman

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

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

From: Linmao Li <[email protected]>

[ Upstream commit c38cce70adef874c2a7b5132c14d6c221401deff ]

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.

mlxbf_pmc_probe() passes the result of ACPI_COMPANION() to acpi_device_hid(), which dereferences it, so force-binding the driver to a device without an ACPI companion leads to a NULL pointer dereference.

Accordingly, add a requisite ACPI_COMPANION() check against NULL to the mlxbf-pmc driver and return -ENODEV when the companion is missing.

Fixes 1a218d312e65 ("platform/mellanox: mlxbf-pmc: Add Mellanox BlueField PMC driver")
---
 drivers/platform/mellanox/mlxbf-pmc.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/platform/mellanox/mlxbf-pmc.c +8 -2
index 67d9b19731edf..fcc8d9eaf37c1 100644
@@ -2021,13 +2021,19 @@ static int mlxbf_pmc_map_counters(struct device *dev)
 
 static int mlxbf_pmc_probe(struct platform_device *pdev)
 {
-	struct acpi_device *acpi_dev = ACPI_COMPANION(&pdev->dev);
-	const char *hid = acpi_device_hid(acpi_dev);
 	struct device *dev = &pdev->dev;
+	struct acpi_device *acpi_dev;
 	struct arm_smccc_res res;
+	const char *hid;
 	guid_t guid;
 	int ret;
 
+	acpi_dev = ACPI_COMPANION(&pdev->dev);
+	if (!acpi_dev)
+		return -ENODEV;
+
+	hid = acpi_device_hid(acpi_dev);
+
 	/* Ensure we have the UUID we expect for this service. */
 	arm_smccc_smc(MLXBF_PMC_SIP_SVC_UID, 0, 0, 0, 0, 0, 0, 0, &res);
 	guid_parse(mlxbf_pmc_svc_uuid_str, &guid);
Signature · 1 line
2.53.0
author maintainer
#509 lore raw

PATCH 492/1376 platform/surface: acpi-notify: Check ACPI companion before use

In reply to Greg Kroah-Hartman

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

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

From: Linmao Li <[email protected]>

[ Upstream commit 2b3a5dabe89e330413af403246b648c1890f368f ]

Since 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(), platform drivers that rely on the existence of a device's ACPI companion object should verify its presence.

san_probe() dereferences the result of ACPI_COMPANION() when installing the GSBUS address space handler, so force-binding the driver to a device without an ACPI companion leads to a NULL pointer dereference. The dereference was introduced when the probe function was switched from ACPI_HANDLE() to ACPI_COMPANION().

Check the ACPI companion against NULL and return -ENODEV when it is missing, like commit e4865a56d013 ("ACPI: driver: Check ACPI_COMPANION() against NULL during probe") does for the core ACPI platform drivers.

Fixes a9e10e587304 ("ACPI: scan: Extend acpi_walk_dep_device_list()")
---
 drivers/platform/surface/surface_acpi_notify.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/platform/surface/surface_acpi_notify.c +5 -1
index 14a9d8a267cbb..7651075572d6e 100644
@@ -777,12 +777,16 @@ static int san_consumer_links_setup(struct platform_device *pdev)
 
 static int san_probe(struct platform_device *pdev)
 {
-	struct acpi_device *san = ACPI_COMPANION(&pdev->dev);
 	struct ssam_controller *ctrl;
+	struct acpi_device *san;
 	struct san_data *data;
 	acpi_status astatus;
 	int status;
 
+	san = ACPI_COMPANION(&pdev->dev);
+	if (!san)
+		return -ENODEV;
+
 	ctrl = ssam_client_bind(&pdev->dev);
 	if (IS_ERR(ctrl))
 		return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl);
Signature · 1 line
2.53.0
author maintainer
#510 lore raw

PATCH 493/1376 usb: mtu3: allow system suspend during active gadget connection

In reply to Greg Kroah-Hartman

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

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

From: Fei Shao <[email protected]>

[ Upstream commit e69027c25361b6044c7928715667586cc5469063 ]

When operating in gadget mode connected to a USB host, system suspend fails with -EBUSY because active peripheral connections block suspend entry.

Fix this by restricting the -EBUSY check to runtime autosuspend (PMSG_IS_AUTO). For system suspend (!PMSG_IS_AUTO), perform soft disconnect to disconnect from the bus and allow MAC sleep.

Fixes 427c66422e14 ("usb: mtu3: support suspend/resume for device mode")
---
 drivers/usb/mtu3/mtu3_core.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
drivers/usb/mtu3/mtu3_core.c +10 -1
index a3a6282893d09..ca8cb6c3a01bf 100644
@@ -1037,9 +1037,14 @@ int ssusb_gadget_suspend(struct ssusb_mtk *ssusb, pm_message_t msg)
 	if (!mtu->gadget_driver)
 		return 0;
 
-	if (mtu->connected)
+	/* Prevent runtime suspend when active connection exists */
+	if (mtu->connected && PMSG_IS_AUTO(msg))
 		return -EBUSY;
 
+	/* Perform soft disconnect for system suspend */
+	if (mtu->softconnect && !PMSG_IS_AUTO(msg))
+		mtu3_dev_on_off(mtu, 0);
+
 	mtu3_dev_suspend(mtu);
 	synchronize_irq(mtu->irq);
 
@@ -1055,5 +1060,9 @@ int ssusb_gadget_resume(struct ssusb_mtk *ssusb, pm_message_t msg)
 
 	mtu3_dev_resume(mtu);
 
+	/* Restore soft connect for system resume */
+	if (mtu->softconnect && !PMSG_IS_AUTO(msg))
+		mtu3_dev_on_off(mtu, 1);
+
 	return 0;
 }
Signature · 1 line
2.53.0
author maintainer
#511 lore raw

PATCH 494/1376 usb: renesas_usbhs: Fix power-off ordering on unbind

In reply to Greg Kroah-Hartman

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

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

From: Biju Das <[email protected]>

[ Upstream commit 589b9e6f96be6bd8dd0d45fda8e948c31dc2fe94 ]

Move the usbhsc_power_ctrl() call to before hardware_exit() and reset_control_assert() in usbhs_remove(), so the PHY is powered off while priv->phy is still valid, rather than after hardware_exit() has already cleared it.

Fixes eb9ac779830b ("usb: renesas_usbhs: Fix synchronous external abort on unbind")
---
 drivers/usb/renesas_usbhs/common.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/usb/renesas_usbhs/common.c +3 -3
index ef9c3bd950ca4..75600dc6703d2 100644
@@ -809,9 +809,6 @@ static void usbhs_remove(struct platform_device *pdev)
 
 	flush_delayed_work(&priv->notify_hotplug_work);
 
-	usbhs_platform_call(priv, hardware_exit, pdev);
-	reset_control_assert(priv->rsts);
-
 	/*
 	 * Explicitly free the IRQ to ensure the interrupt handler is
 	 * disabled and synchronized before freeing resources.
@@ -828,6 +825,9 @@ static void usbhs_remove(struct platform_device *pdev)
 	if (!usbhs_get_dparam(priv, runtime_pwctrl))
 		usbhsc_power_ctrl(priv, 0);
 
+	usbhs_platform_call(priv, hardware_exit, pdev);
+	reset_control_assert(priv->rsts);
+
 	usbhsc_clk_put(priv);
 	pm_runtime_disable(&pdev->dev);
 }
Signature · 1 line
2.53.0
author maintainer
#512 lore raw

PATCH 495/1376 drm/panel: samsung-s6d16d0: Power off on prepare failure

In reply to Greg Kroah-Hartman

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

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

From: Laxman Acharya Padhya <[email protected]>

[ Upstream commit a9f950adfe2147318d75e7a6eab5e814851802ac ]

If enabling tearing mode or exiting sleep mode fails after the regulator is enabled, s6d16d0_prepare() returns without asserting reset or disabling the supply. Since the DRM panel core leaves the panel unprepared, a later unprepare call skips the driver callback and the supply remains enabled.

Assert reset and disable the supply before returning the DSI command error.

Fixes ac1d6d74884e ("drm/panel: Add driver for Samsung S6D16D0 panel")
Assisted-by Codex:gpt-5
---
 drivers/gpu/drm/panel/panel-samsung-s6d16d0.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/gpu/drm/panel/panel-samsung-s6d16d0.c +8 -2
index 79f611963c618..f73b603be0b0b 100644
@@ -89,16 +89,22 @@ static int s6d16d0_prepare(struct drm_panel *panel)
 				       MIPI_DSI_DCS_TEAR_MODE_VBLANK);
 	if (ret) {
 		dev_err(s6->dev, "failed to enable vblank TE (%d)\n", ret);
-		return ret;
+		goto err_power_off;
 	}
 	/* Exit sleep mode and power on */
 	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
 	if (ret) {
 		dev_err(s6->dev, "failed to exit sleep mode (%d)\n", ret);
-		return ret;
+		goto err_power_off;
 	}
 
 	return 0;
+
+err_power_off:
+	gpiod_set_value_cansleep(s6->reset_gpio, 1);
+	regulator_disable(s6->supply);
+
+	return ret;
 }
 
 static int s6d16d0_enable(struct drm_panel *panel)
Signature · 1 line
2.53.0
author maintainer
#513 lore raw

PATCH 496/1376 perf metricgroup: Fix metric expression copy leaks

In reply to Greg Kroah-Hartman

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

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

From: Yu Peng <[email protected]>

[ Upstream commit ef3af1df4f3372bd8ad47619452a283048b3bc8d ]

metricgroup__copy_metric_events() allocates a new metric expression and duplicates metric_name before linking the expression into the destination metric event.

Free new_expr when strdup() fails, and free the duplicated metric_name on the later error paths.

Fixes b85a4d61d302 ("perf metric: Allow modifiers on metrics")
---
 tools/perf/util/metricgroup.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
tools/perf/util/metricgroup.c +6 -1
index 4dff3e925a47b..6d6bfcebb97a8 100644
@@ -1814,8 +1814,10 @@ int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp,
 			new_expr->metric_expr = old_expr->metric_expr;
 			new_expr->metric_threshold = old_expr->metric_threshold;
 			new_expr->metric_name = strdup(old_expr->metric_name);
-			if (!new_expr->metric_name)
+			if (!new_expr->metric_name) {
+				free(new_expr);
 				return -ENOMEM;
+			}
 
 			new_expr->metric_unit = old_expr->metric_unit;
 			new_expr->runtime = old_expr->runtime;
@@ -1827,6 +1829,7 @@ int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp,
 				alloc_size = sizeof(*new_expr->metric_refs);
 				new_expr->metric_refs = calloc(nr + 1, alloc_size);
 				if (!new_expr->metric_refs) {
+					zfree(&new_expr->metric_name);
 					free(new_expr);
 					return -ENOMEM;
 				}
@@ -1843,6 +1846,7 @@ int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp,
 			alloc_size = sizeof(*new_expr->metric_events);
 			new_expr->metric_events = calloc(nr + 1, alloc_size);
 			if (!new_expr->metric_events) {
+				zfree(&new_expr->metric_name);
 				zfree(&new_expr->metric_refs);
 				free(new_expr);
 				return -ENOMEM;
@@ -1853,6 +1857,7 @@ int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp,
 				evsel = old_expr->metric_events[idx];
 				evsel = evlist__find_evsel(evlist, evsel->core.idx);
 				if (evsel == NULL) {
+					zfree(&new_expr->metric_name);
 					zfree(&new_expr->metric_events);
 					zfree(&new_expr->metric_refs);
 					free(new_expr);
Signature · 1 line
2.53.0
author maintainer
#514 lore raw

PATCH 497/1376 soc: qcom: rpmh-rsc: manage PM notifiers with devres

In reply to Greg Kroah-Hartman

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

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

From: Pengpeng Hou <[email protected]>

[ Upstream commit 75e918aa876440d8ad559a11d6ab87bddb1ed79a ]

rpmh_rsc_probe() registers CPU PM or genpd notifiers before populating child devices. If child population fails, the CPU PM notifier path is not unwound and the genpd path needs open-coded cleanup.

Use devm_pm_runtime_enable() for the genpd path and devm_add_action_or_reset() for both notifier registrations. This makes probe failure and driver detach use the same cleanup model while keeping devm_of_platform_populate() responsible for child devices.

Fixes 25092e6100ac ("soc: qcom: rpmh-rsc: Attach RSC to cluster PM domain")
---
 drivers/soc/qcom/rpmh-rsc.c | 37 ++++++++++++++++++++++++++-----------
 1 file changed, 26 insertions(+), 11 deletions(-)
drivers/soc/qcom/rpmh-rsc.c +26 -11
index cc72a31a450e4..1b0b7081c9515 100644
@@ -944,17 +944,30 @@ static int rpmh_rsc_pd_callback(struct notifier_block *nfb,
 	return NOTIFY_OK;
 }
 
+static void rpmh_rsc_pd_detach(void *data)
+{
+	dev_pm_genpd_remove_notifier(data);
+}
+
 static int rpmh_rsc_pd_attach(struct rsc_drv *drv, struct device *dev)
 {
 	int ret;
 
-	pm_runtime_enable(dev);
+	ret = devm_pm_runtime_enable(dev);
+	if (ret)
+		return ret;
+
 	drv->genpd_nb.notifier_call = rpmh_rsc_pd_callback;
 	ret = dev_pm_genpd_add_notifier(dev, &drv->genpd_nb);
 	if (ret)
-		pm_runtime_disable(dev);
+		return ret;
 
-	return ret;
+	return devm_add_action_or_reset(dev, rpmh_rsc_pd_detach, dev);
+}
+
+static void rpmh_rsc_cpu_pm_unregister(void *data)
+{
+	cpu_pm_unregister_notifier(data);
 }
 
 static int rpmh_probe_tcs_config(struct platform_device *pdev, struct rsc_drv *drv)
@@ -1110,7 +1123,15 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
 				return ret;
 		} else {
 			drv->rsc_pm.notifier_call = rpmh_rsc_cpu_pm_callback;
-			cpu_pm_register_notifier(&drv->rsc_pm);
+			ret = cpu_pm_register_notifier(&drv->rsc_pm);
+			if (ret)
+				return ret;
+
+			ret = devm_add_action_or_reset(&pdev->dev,
+						       rpmh_rsc_cpu_pm_unregister,
+						       &drv->rsc_pm);
+			if (ret)
+				return ret;
 		}
 	}
 
@@ -1125,13 +1146,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
 	dev_set_drvdata(&pdev->dev, drv);
 	drv->dev = &pdev->dev;
 
-	ret = devm_of_platform_populate(&pdev->dev);
-	if (ret && pdev->dev.pm_domain) {
-		dev_pm_genpd_remove_notifier(&pdev->dev);
-		pm_runtime_disable(&pdev->dev);
-	}
-
-	return ret;
+	return devm_of_platform_populate(&pdev->dev);
 }
 
 static const struct of_device_id rpmh_drv_match[] = {
Signature · 1 line
2.53.0
author maintainer
#515 lore raw

PATCH 498/1376 bus: qcom-ebi2: use managed resources for clocks and children

In reply to Greg Kroah-Hartman

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

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

From: Pengpeng Hou <[email protected]>

[ Upstream commit d19a46f7ed8eb54fea61e0eaf7db53ff7babb03c ]

qcom_ebi2_probe() enables the EBI2 clocks manually and populates child devices manually. Several later failure paths can then return without disabling the clocks or without relying on the driver core to undo child population.

Use devm_clk_get_enabled() for both clocks and devm_of_platform_populate() for children. This lets the driver core unwind the resources automatically and removes the hand-written error labels.

---
 drivers/bus/qcom-ebi2.c | 50 +++++++++--------------------------------
 1 file changed, 11 insertions(+), 39 deletions(-)
drivers/bus/qcom-ebi2.c +11 -39
index ab00c75b9e953..8d2eb955dc921 100644
@@ -302,41 +302,23 @@ static int qcom_ebi2_probe(struct platform_device *pdev)
 	u32 val;
 	int ret;
 
-	ebi2xclk = devm_clk_get(dev, "ebi2x");
+	ebi2xclk = devm_clk_get_enabled(dev, "ebi2x");
 	if (IS_ERR(ebi2xclk))
 		return PTR_ERR(ebi2xclk);
 
-	ret = clk_prepare_enable(ebi2xclk);
-	if (ret) {
-		dev_err(dev, "could not enable EBI2X clk (%d)\n", ret);
-		return ret;
-	}
-
-	ebi2clk = devm_clk_get(dev, "ebi2");
-	if (IS_ERR(ebi2clk)) {
-		ret = PTR_ERR(ebi2clk);
-		goto err_disable_2x_clk;
-	}
-
-	ret = clk_prepare_enable(ebi2clk);
-	if (ret) {
-		dev_err(dev, "could not enable EBI2 clk\n");
-		goto err_disable_2x_clk;
-	}
+	ebi2clk = devm_clk_get_enabled(dev, "ebi2");
+	if (IS_ERR(ebi2clk))
+		return PTR_ERR(ebi2clk);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	ebi2_base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(ebi2_base)) {
-		ret = PTR_ERR(ebi2_base);
-		goto err_disable_clk;
-	}
+	if (IS_ERR(ebi2_base))
+		return PTR_ERR(ebi2_base);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 	ebi2_xmem = devm_ioremap_resource(dev, res);
-	if (IS_ERR(ebi2_xmem)) {
-		ret = PTR_ERR(ebi2_xmem);
-		goto err_disable_clk;
-	}
+	if (IS_ERR(ebi2_xmem))
+		return PTR_ERR(ebi2_xmem);
 
 	/* Allegedly this turns the power save mode off */
 	writel(0UL, ebi2_xmem + EBI2_XMEM_CFG);
@@ -353,7 +335,7 @@ static int qcom_ebi2_probe(struct platform_device *pdev)
 		/* Figure out the chipselect */
 		ret = of_property_read_u32(child, "reg", &csindex);
 		if (ret)
-			goto err_disable_clk;
+			return ret;
 
 		if (csindex > 5) {
 			dev_err(dev,
@@ -372,20 +354,10 @@ static int qcom_ebi2_probe(struct platform_device *pdev)
 		have_children = true;
 	}
 
-	if (have_children) {
-		ret = of_platform_default_populate(np, NULL, dev);
-		if (ret)
-			goto err_disable_clk;
-	}
+	if (have_children)
+		return devm_of_platform_populate(dev);
 
 	return 0;
-
-err_disable_clk:
-	clk_disable_unprepare(ebi2clk);
-err_disable_2x_clk:
-	clk_disable_unprepare(ebi2xclk);
-
-	return ret;
 }
 
 static const struct of_device_id qcom_ebi2_of_match[] = {
Signature · 1 line
2.53.0
author maintainer
#516 lore raw

PATCH 499/1376 clk: qcom: camcc-sc8280xp: unregister CAMCC_GDSC_CLK

In reply to Greg Kroah-Hartman

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

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

From: Brian Masney <[email protected]>

[ Upstream commit 499b4cb6710f9a351d8b57a2132f9b4389d8464a ]

With the introduction of sync_state support in the clk and pmdomain subsystems, the following warning happens when the unused clocks are shutdown in camcc-sc8280xp:

    [   15.408367] titan_top_gdsc status stuck at 'on'
    [   15.408429] WARNING: drivers/clk/qcom/gdsc.c:178 at gdsc_toggle_logic+0x14c/0x160, CPU#2: kworker/u32:1/14
    [   15.408462] Modules linked in: bnep vfat fat ath11k_pci(+) ath11k mac80211 cfg80211 mhi libarc4 snd_soc_wcd938x snd_soc_wcd938x_sdw snd_soc_wcd_classh hci_uart snd_soc_wcd_common
    snd_soc_sc8280xp soundwire_qcom snd_soc_wcd_mbhc snd_soc_qcom_sdw slimbus snd_soc_qcom_common regmap_sdw btqca btrtl qcom_camss soundwire_bus btbcm btintel snd_soc_sdca snd_soc_lpass_wsa_macro
    bluetooth snd_soc_lpass_tx_macro snd_soc_lpass_va_macro snd_soc_lpass_rx_macro snd_soc_hdmi_codec snd_soc_lpass_macro_common videobuf2_dma_sg ov5675 v4l2_fwnode videobuf2_memops
    qcom_spmi_adc5 snd_soc_core qcom_spmi_adc_tm5 videobuf2_v4l2 snd_seq snd_seq_device videobuf2_common v4l2_async qcom_vadc_common qcom_spmi_temp_alarm pm8941_pwrkey industrialio videodev
    snd_compress rfkill ac97_bus snd_pcm_dmaengine qcom_tsens mc qcom_edac snd_pcm pci_pwrctrl_pwrseq qcom_cpufreq_hw snd_timer snd qcomtee soundcore tee leds_gpio joydev binfmt_misc zram
    lz4hc_compress governor_simpleondemand panel_edp msm xhci_plat_hcd nvme nvme_core dwc3 qcom_pm8008_regulator
    [   15.408688]  ucsi_glink nvme_keyring nvme_auth pmic_glink_altmode udc_core typec_ucsi aux_hpd_bridge qcom_battmgr ulpi ubwc_config socinfo ocmem drm_gpuvm qcom_q6v5_pas drm_exec
    qcom_pil_info leds_qcom_lpg gpu_sched led_class_multicolor rtc_pm8xxx qcom_pbs qcom_common drm_display_helper qcom_pon qcom_glink_smem qcom_glink ghash_ce pwrseq_qcom_wcn gpio_sbu_mux
    qcom_stats phy_qcom_qmp_combo qcom_q6v5 gf128mul cec dispcc_sc8280xp phy_qcom_edp camcc_sc8280xp i2c_qcom_cci qcom_sysmon drm_dp_aux_bus mdt_loader aux_bridge qcom_pm8008 i2c_hid_of_elan
    dwc3_qcom_legacy llcc_qcom icc_bwmon gpi typec qcom_refgen_regulator phy_qcom_qmp_usb nvmem_qfprom qcom_ipcc phy_qcom_snps_femto_v2 gpucc_sc8280xp pinctrl_sc8280xp_lpass_lpi qcom_hwspinlock
    pinctrl_lpass_lpi lpasscc_sc8280xp qrtr qcom_aoss pmic_glink pdr_interface phy_qcom_qmp_pcie qcom_smd qcom_pdr_msg icc_osm_l3 qcom_wdt qmi_helpers qcom_rng smp2p rpmsg_core gpio_keys pwm_bl
    smem hid_multitouch fuse i2c_dev
    [   15.408928] CPU: 2 UID: 0 PID: 14 Comm: kworker/u32:1 Not tainted 7.1.0+ #2 PREEMPT(lazy)
    [   15.408937] Hardware name: LENOVO 21BX0016US/21BX0016US, BIOS N3HET88W (1.60 ) 03/14/2024
    [   15.408942] Workqueue: pm pm_runtime_work
    [   15.408959] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
    [   15.408967] pc : gdsc_toggle_logic+0x14c/0x160
    [   15.408978] lr : gdsc_toggle_logic+0x14c/0x160
    [   15.408987] sp : ffff8000800f3b40
    [   15.408991] x29: ffff8000800f3b40 x28: 0000000000000000 x27: 0000000000000000
    [   15.409003] x26: 0000000000000000 x25: 0000000000000000 x24: 0000000000000000
    [   15.409014] x23: 0000000000000000 x22: 0000000000000001 x21: ffffa33f298fca88
    [   15.409024] x20: 0000000000000000 x19: ffffa33f298fc5b0 x18: 00cd15db75dacefd
    [   15.409035] x17: 000000040044ffff x16: ffffa33f3b1a3d88 x15: 726f776b80000002
    [   15.409045] x14: ffffffffffffffff x13: 0000000000000028 x12: 0101010101010101
    [   15.409056] x11: 7f7f7f7f7f7f7f7f x10: fefeff3039313274 x9 : ffffa33f3a5edafc
    [   15.409067] x8 : ffff8000800f3780 x7 : 0000000000000001 x6 : 0000000000000001
    [   15.409078] x5 : ffff000bf3ca1288 x4 : 0000000000000000 x3 : ffff5cccb6a3f000
    [   15.409088] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff000080ae0000
    [   15.409098] Call trace:
    [   15.409103]  gdsc_toggle_logic+0x14c/0x160 (P)
    [   15.409115]  gdsc_disable+0x4c/0x190
    [   15.409126]  _genpd_power_off+0xa0/0x1a8
    [   15.409137]  genpd_power_off.part.0+0x180/0x2a0
    [   15.409149]  genpd_runtime_suspend+0x218/0x310
    [   15.409155]  __rpm_callback+0x50/0x1f8
    [   15.409166]  rpm_callback+0x7c/0x90
    [   15.409175]  rpm_suspend+0xe8/0x690
    [   15.409185]  pm_runtime_work+0xd0/0xe0
    [   15.409195]  process_one_work+0x18c/0x518
    [   15.409208]  worker_thread+0x190/0x320
    [   15.409218]  kthread+0x110/0x130
    [   15.409227]  ret_from_fork+0x10/0x20

This clock is force enabled to be on in the probe, and registered with the Common Clk Framework, resulting in them being toggled off after unused clocks are shutdown. This clock is required for the GDSC transitions.

Similar to the fix in commit b60521eff227 ("clk: qcom: gcc-x1e80100:
Unregister GCC_GPU_CFG_AHB_CLK/GCC_DISP_XO_CLK"), let's just unregister this clock.

---
 drivers/clk/qcom/camcc-sc8280xp.c | 19 -------------------
 1 file changed, 19 deletions(-)
drivers/clk/qcom/camcc-sc8280xp.c +0 -19
index 479964f916086..cf170fc7baf1b 100644
@@ -1754,24 +1754,6 @@ static struct clk_branch camcc_csiphy3_clk = {
 	},
 };
 
-static struct clk_branch camcc_gdsc_clk = {
-	.halt_reg = 0xc1e4,
-	.halt_check = BRANCH_HALT,
-	.clkr = {
-		.enable_reg = 0xc1e4,
-		.enable_mask = BIT(0),
-		.hw.init = &(struct clk_init_data){
-			.name = "camcc_gdsc_clk",
-			.parent_hws = (const struct clk_hw*[]){
-				&camcc_xo_clk_src.clkr.hw,
-			},
-			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
-			.ops = &clk_branch2_ops,
-		},
-	},
-};
-
 static struct clk_branch camcc_icp_ahb_clk = {
 	.halt_reg = 0xc0d8,
 	.halt_check = BRANCH_HALT,
@@ -2840,7 +2822,6 @@ static struct clk_regmap *camcc_sc8280xp_clocks[] = {
 	[CAMCC_CSIPHY2_CLK] = &camcc_csiphy2_clk.clkr,
 	[CAMCC_CSIPHY3_CLK] = &camcc_csiphy3_clk.clkr,
 	[CAMCC_FAST_AHB_CLK_SRC] = &camcc_fast_ahb_clk_src.clkr,
-	[CAMCC_GDSC_CLK] = &camcc_gdsc_clk.clkr,
 	[CAMCC_ICP_AHB_CLK] = &camcc_icp_ahb_clk.clkr,
 	[CAMCC_ICP_CLK] = &camcc_icp_clk.clkr,
 	[CAMCC_ICP_CLK_SRC] = &camcc_icp_clk_src.clkr,
Signature · 1 line
2.53.0
author maintainer
#517 lore raw

PATCH 500/1376 iio: accel: dmard09: Implement IIO_CHAN_INFO_SCALE

In reply to Greg Kroah-Hartman

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

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

From: Mert Seftali <[email protected]>

[ Upstream commit aa58ecc73466d0cb8c418de98e2225490bf600e3 ]

Reading the in_accel_scale attribute on the DMARD09 has always returned -EINVAL: the channels advertise scale via info_mask_shared_by_type so the IIO core exposes the attribute, but dmard09_read_raw() only handles IIO_CHAN_INFO_RAW, so a SCALE read falls through to 'default: return -EINVAL':

    $ cat .../iio:deviceX/in_accel_scale
    cat: in_accel_scale: Invalid argument

leaving userspace with raw counts it cannot convert to m/s^2.

The driver was written from a vendor source [1] without a datasheet, and the scale was declared but never implemented. The vendor source carries the sensitivity: its conversion is

    acc = raw * GRAVITY_EARTH_1000 / sensitivity   (then / 1000 -> m/s^2)

with sensitivity = 32 and GRAVITY_EARTH_1000 = 9807 ("about (9.80665)*1000"), i.e. 32 counts correspond to 1 g.

That sensitivity applies to the value this driver already reports as raw:
the vendor reduces each 16-bit sample to a signed 9-bit value, and the preparation in dmard09_read_raw() yields the same value. It is
self-consistent: 256 counts / 32 = 8 g full scale, matching the +/-8g range.

Implement the scale derived from that sensitivity using standard gravity:

    scale = 9.80665 / 32 = 0.3064578125 m/s^2 per LSB
---
 drivers/iio/accel/dmard09.c | 7 +++++++
 1 file changed, 7 insertions(+)
drivers/iio/accel/dmard09.c +7 -0
index 4ec70ca6910d5..117cebbeb1387 100644
@@ -8,6 +8,7 @@
 #include <linux/unaligned.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
+#include <linux/units.h>
 #include <linux/iio/iio.h>
 
 #define DMARD09_DRV_NAME	"dmard09"
@@ -79,6 +80,12 @@ static int dmard09_read_raw(struct iio_dev *indio_dev,
 		*val = accel;
 
 		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		*val = 0;
+		/* 1 g / 32 LSB, in m/s^2 */
+		*val2 = IIO_G_TO_M_S_2(NANO / 32);
+
+		return IIO_VAL_INT_PLUS_NANO;
 	default:
 		return -EINVAL;
 	}
Signature · 1 line
2.53.0
author maintainer
#518 lore raw

PATCH 501/1376 RDMA/core: Wait for RCU callbacks before unloading ib_core

In reply to Greg Kroah-Hartman

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

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

From: Leon Romanovsky <[email protected]>

[ Upstream commit 7d75592114d1664623c8cf191a12b38052c04483 ]

put_gid_ndev() is queued with call_rcu() and implemented in ib_core. Stopping the workqueues does not drain callbacks already queued, so RCU could invoke it after the module code has been unloaded.

synchronize_rcu() does not wait for callbacks. Wait for them after all producers have stopped.

---
 drivers/infiniband/core/device.c | 1 +
 1 file changed, 1 insertion(+)
drivers/infiniband/core/device.c +1 -0
index 666ce83cc35c4..cd53e9c4f913b 100644
@@ -3017,6 +3017,7 @@ static void __exit ib_core_cleanup(void)
 	/* Make sure that any pending umem accounting work is done. */
 	destroy_workqueue(ib_wq);
 	destroy_workqueue(ib_unreg_wq);
+	rcu_barrier();
 	WARN_ON(!xa_empty(&clients));
 	WARN_ON(!xa_empty(&devices));
 }
Signature · 1 line
2.53.0
author maintainer
#519 lore raw

PATCH 502/1376 RDMA/mlx5: Drain RCU callbacks during module teardown

In reply to Greg Kroah-Hartman

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

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

From: Leon Romanovsky <[email protected]>

[ Upstream commit e37cdd75f8d61c1123d324ae5667ac3da562290e ]

devx_free_subscription() can remain queued after the last DevX event file drops its module reference or an auxiliary driver detaches its devices. mlx5_ib can then unload before the callback runs.

Registration error unwind has the same risk because driver registration can attach existing devices before failing. Wait after all drivers have stopped.

---
 drivers/infiniband/hw/mlx5/main.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/infiniband/hw/mlx5/main.c +2 -0
index edd38510c0259..a0b3086381951 100644
@@ -5101,6 +5101,7 @@ static int __init mlx5_ib_init(void)
 dd_err:
 	mlx5r_rep_cleanup();
 rep_err:
+	rcu_barrier();
 	mlx5_ib_qp_event_cleanup();
 qp_event_err:
 	destroy_workqueue(mlx5_ib_event_wq);
@@ -5114,6 +5115,7 @@ static void __exit mlx5_ib_cleanup(void)
 	auxiliary_driver_unregister(&mlx5r_driver);
 	auxiliary_driver_unregister(&mlx5r_mp_driver);
 	mlx5r_rep_cleanup();
+	rcu_barrier();
 
 	mlx5_ib_qp_event_cleanup();
 	destroy_workqueue(mlx5_ib_event_wq);
Signature · 1 line
2.53.0
author maintainer
#520 lore raw

PATCH 503/1376 RDMA/ipoib: Drain RCU callbacks during module teardown

In reply to Greg Kroah-Hartman

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

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

From: Leon Romanovsky <[email protected]>

[ Upstream commit 31b7c700670830a0e8a4cdcd451c88a13cc5dc48 ]

IPoIB reclamation completions can be signaled from inside an RCU callback. Teardown can wake before the callback returns and unload ib_ipoib while its code is still executing.

Client registration failure can also remove already-added devices and queue callbacks. Wait after client and workqueue teardown.

---
 drivers/infiniband/ulp/ipoib/ipoib_main.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/infiniband/ulp/ipoib/ipoib_main.c +2 -0
index d65f3a5963651..bbb00fdc12db3 100644
@@ -2703,6 +2703,7 @@ static int __init ipoib_init_module(void)
 err_sa:
 	ib_sa_unregister_client(&ipoib_sa_client);
 	destroy_workqueue(ipoib_workqueue);
+	rcu_barrier();
 
 err_fs:
 	ipoib_unregister_debugfs();
@@ -2720,6 +2721,7 @@ static void __exit ipoib_cleanup_module(void)
 	ib_sa_unregister_client(&ipoib_sa_client);
 	ipoib_unregister_debugfs();
 	destroy_workqueue(ipoib_workqueue);
+	rcu_barrier();
 }
 
 module_init(ipoib_init_module);
Signature · 1 line
2.53.0
author maintainer
#521 lore raw

PATCH 504/1376 RDMA/rxe: Avoid reprocessing the current packet after the QP enters the error state

In reply to Greg Kroah-Hartman

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

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

From: Allison Henderson <[email protected]>

[ Upstream commit 15ae32c4a3551c4c9da457370bdfdd65d171e512 ]

When do_complete() finds the QP in the error state it returns RESPST_CHK_RESOURCE. Before commit 49dc9c1f0c7e ("RDMA/rxe: Cleanup reset state handling in rxe_resp.c") this was the flush loop:
check_resource() had an error-state branch that fetched each remaining recv WQE and completed it with IB_WC_WR_FLUSH_ERR, without touching the current packet. That commit removed the error-state branch from check_resource() (draining is now done at rxe_receiver() entry) but kept the do_complete() error-state return.

As a result, when a QP moves to the error state while a packet is being completed - e.g. an rdma_cm disconnect racing with receive processing - the responder state machine loops back into the request processing chain with the already-completed packet still in hand:
check_resource() fetches a fresh recv WQE, execute()/send_data_in() copies the same packet payload again, do_complete() posts another IB_WC_SUCCESS CQE (qp->resp.status is still 0), and control returns to the error-state check. The loop re-executes the same packet once per posted recv WQE (observed: ~1000 duplicate IB_WC_SUCCESS completions of one SEND, one per ~8us, matching the RQ occupancy) until the RQ is exhausted, after which qp->resp.wqe is NULL and send_data_in() dereferences it:

  BUG: kernel NULL pointer dereference, address: 0000000000000014
  Workqueue: rxe_wq do_work
  RIP: copy_data+0x29/0x1f0
  Call Trace:
   send_data_in+0x25/0x50
   rxe_receiver+0xf36/0x1dd0

The duplicate completions are indistinguishable from real receives to the ULP. During an rds stress test, the message was accepted as new and delivered the same datagram to user space hundreds of times, corrupting the stream; any ULP that relies on RC exactly-once delivery is affected.

A live packet reaching the error-state check in do_complete() has been executed and completed exactly once and must be consumed, not re-processed. Return RESPST_CLEANUP for it (dequeue and free); keep returning RESPST_CHK_RESOURCE for the pkt == NULL case.

Fixes 49dc9c1f0c7e ("RDMA/rxe: Cleanup reset state handling in rxe_resp.c")
Assisted-by Claude-Code:claude-fable-5
---
 drivers/infiniband/sw/rxe/rxe_resp.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/infiniband/sw/rxe/rxe_resp.c +8 -1
index 5611f63a1115c..abf6cf3ce986b 100644
@@ -1188,7 +1188,14 @@ static enum resp_states do_complete(struct rxe_qp *qp,
 	spin_lock_irqsave(&qp->state_lock, flags);
 	if (unlikely(qp_state(qp) == IB_QPS_ERR)) {
 		spin_unlock_irqrestore(&qp->state_lock, flags);
-		return RESPST_CHK_RESOURCE;
+		/* The packet was executed and completed before the QP
+		 * moved to ERROR; it must be consumed exactly once.
+		 * Re-entering the request chain with the stale packet
+		 * would copy it into every remaining recv WQE as a new
+		 * completion.  Remaining WQEs are flushed by the drain
+		 * path at rxe_receiver() entry.
+		 */
+		return pkt ? RESPST_CLEANUP : RESPST_CHK_RESOURCE;
 	}
 	spin_unlock_irqrestore(&qp->state_lock, flags);
 
Signature · 1 line
2.53.0
author maintainer
#522 lore raw

PATCH 505/1376 crypto: ccp - Fix memory leak in SEV INIT_EX path

In reply to Greg Kroah-Hartman

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

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

From: Atish Patra <[email protected]>

[ Upstream commit c8e53ada20d352b0f1bdc3e58405a9edab897a2e ]

allocated pages in _init_ext_path are never freed and sev_init_ex_buffer is left pointing at the leaked memory in case of any failures during the function..

Fix by adding an error path that frees the pages and clears sev_init_ex_buffer. Make sure we only free the memory if the failure happens before the conversion. Otherwise, we may end up trying to free up converted pages in case of reclaim failure. rmp_mark_pages_firmware failures should be rare enough to avoid more code complexity to track down which pages were reclaimed/leaked vs which are not.

Fixes 7364a6fbca45 ("crypto: ccp: Handle non-volatile INIT_EX data when SNP is enabled")
---
 drivers/crypto/ccp/sev-dev.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)
drivers/crypto/ccp/sev-dev.c +14 -3
index d6a0773d6da8f..6dc380537ece9 100644
@@ -1244,7 +1244,7 @@ static int __sev_platform_init_handle_init_ex_path(struct sev_device *sev)
 	if (sev_init_ex_buffer)
 		return 0;
 
-	page = alloc_pages(GFP_KERNEL, get_order(NV_LENGTH));
+	page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(NV_LENGTH));
 	if (!page) {
 		dev_err(sev->dev, "SEV: INIT_EX NV memory allocation failed\n");
 		return -ENOMEM;
@@ -1254,7 +1254,7 @@ static int __sev_platform_init_handle_init_ex_path(struct sev_device *sev)
 
 	rc = sev_read_init_ex_file();
 	if (rc)
-		return rc;
+		goto err_free;
 
 	/* If SEV-SNP is initialized, transition to firmware page. */
 	if (sev->snp_initialized) {
@@ -1263,11 +1263,22 @@ static int __sev_platform_init_handle_init_ex_path(struct sev_device *sev)
 		npages = 1UL << get_order(NV_LENGTH);
 		if (rmp_mark_pages_firmware(__pa(sev_init_ex_buffer), npages, false)) {
 			dev_err(sev->dev, "SEV: INIT_EX NV memory page state change failed.\n");
-			return -ENOMEM;
+			rc = -ENOMEM;
+			/*
+			 * Pages can be in an inconsistent state, don't release them back to the
+			 * system.
+			 */
+			goto err_reset;
 		}
 	}
 
 	return 0;
+
+err_free:
+	__free_pages(page, get_order(NV_LENGTH));
+err_reset:
+	sev_init_ex_buffer = NULL;
+	return rc;
 }
 
 static int __sev_platform_init_locked(int *error)
Signature · 1 line
2.53.0
#523 lore raw

Re: [PATCH 6.12 0505/1376] crypto: ccp - Fix memory leak in SEV INIT_EX path

Hi Greg/Sasha,

Quoted 54 lines · Greg Kroah-Hartman

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

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

From: Atish Patra <[email protected]>

[ Upstream commit c8e53ada20d352b0f1bdc3e58405a9edab897a2e ]

allocated pages in _init_ext_path are never freed and sev_init_ex_buffer is left pointing at the leaked memory in case of any failures during the function..

Fix by adding an error path that frees the pages and clears sev_init_ex_buffer. Make sure we only free the memory if the failure happens before the conversion. Otherwise, we may end up trying to free up converted pages in case of reclaim failure. rmp_mark_pages_firmware failures should be rare enough to avoid more code complexity to track down which pages were reclaimed/leaked vs which are not.

Fixes 7364a6fbca45 ("crypto: ccp: Handle non-volatile INIT_EX data when SNP is enabled")
---
  drivers/crypto/ccp/sev-dev.c | 17 ++++++++++++++---
  1 file changed, 14 insertions(+), 3 deletions(-)
drivers/crypto/ccp/sev-dev.c +2 -2
index d6a0773d6da8f..6dc380537ece9 100644
@@ -1244,7 +1244,7 @@ static int __sev_platform_init_handle_init_ex_path(struct sev_device *sev)
  	if (sev_init_ex_buffer)
  		return 0;
 
-	page = alloc_pages(GFP_KERNEL, get_order(NV_LENGTH));
+	page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(NV_LENGTH));
  	if (!page) {
  		dev_err(sev->dev, "SEV: INIT_EX NV memory allocation failed\n");
  		return -ENOMEM;
@@ -1254,7 +1254,7 @@ static int __sev_platform_init_handle_init_ex_path(struct sev_device *sev)
 
  	rc = sev_read_init_ex_file();
  	if (rc)
-		return rc;
+		goto err_free;
 
  	/* If SEV-SNP is initialized, transition to firmware page. */
  	if (sev->snp_initialized) {

drivers/crypto/ccp/sev-dev.c static int __sev_platform_init_handle_init_ex_path(struct sev_device *sev) · line 1269

Quoted 8 lines
drivers/crypto/ccp/sev-dev.c +4 -1
@@ -1263,11 +1263,22 @@ static int __sev_platform_init_handle_init_ex_path(struct sev_device *sev)
  		npages = 1UL << get_order(NV_LENGTH);
  		if (rmp_mark_pages_firmware(__pa(sev_init_ex_buffer), npages, false)) {
  			dev_err(sev->dev, "SEV: INIT_EX NV memory page state change failed.\n");
-			return -ENOMEM;
+			rc = -ENOMEM;
+			/*
+			 * Pages can be in an inconsistent state, don't release them back to the
+			 * system.

I ran an AI-assisted backport review and manually verified the finding.

Upstream c8e53ada20d3 follows b0e7ec0dab242c5e480121ba12400d0513e37ca2, "crypto: ccp - Fix possible deadlock in SEV init failure path", but 6.12 has only the former. The backport retains locked=false in rmp_mark_pages_firmware() while sev_cmd_mutex is already held.

Upstream code after b0e7ec0dab24:

rmp_mark_pages_firmware(__pa(sev_init_ex_buffer),
npages, true)

Downstream 6.12.y code:

rmp_mark_pages_firmware(__pa(sev_init_ex_buffer),
npages, false)

The downstream false argument can reacquire sev_cmd_mutex in rollback.

If a later page conversion fails, rollback enters snp_reclaim_pages(). The false argument selects sev_do_cmd(), which tries to take the same mutex again, so the cleanup added by this patch cannot finish.

Maybe we should beapplying b0e7ec0dab242c5e480121ba12400d0513e37ca2 to the queue now that this backport is merged.

Thanks,
Harshit> + */

Quoted 14 lines
drivers/crypto/ccp/sev-dev.c +7 -0
+			goto err_reset;
  		}
  	}
 
  	return 0;
+
+err_free:
+	__free_pages(page, get_order(NV_LENGTH));
+err_reset:
+	sev_init_ex_buffer = NULL;
+	return rc;
  }
 
  static int __sev_platform_init_locked(int *error)
maintainer Applied
#524 lore raw

Re: [PATCH 6.12 0505/1376] crypto: ccp - Fix memory leak in SEV INIT_EX path

Quoted 4 lines

Upstream c8e53ada20d3 follows b0e7ec0dab242c5e480121ba12400d0513e37ca2, "crypto: ccp - Fix possible deadlock in SEV init failure path", but 6.12 has only the former. The backport retains locked=false in rmp_mark_pages_firmware() while sev_cmd_mutex is already held.

Queued for 6.18 and 6.12, thanks. 6.18 had the same gap.

Signature · 2 lines
Thanks,
Sasha
#525 lore raw

Re: [PATCH 6.12 0505/1376] crypto: ccp - Fix memory leak in SEV INIT_EX path

Quoted 1 line · Sasha Levin

Queued for 6.18 and 6.12, thanks. 6.18 had the same gap.

thanks!

Regards,
Harshit

author maintainer
#526 lore raw

PATCH 506/1376 hwrng: ks-sa - Fix runtime PM cleanup on registration failure

In reply to Greg Kroah-Hartman

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

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

From: Yuho Choi <[email protected]>

[ Upstream commit 1c17b601fafb09c9ec074fd097737d20eafe7d63 ]

ks_sa_rng_probe() enables runtime PM and resumes the device before registering the hwrng. If devm_hwrng_register() fails, probe returns without dropping the runtime PM usage count or disabling runtime PM.

Unwind the runtime PM state on the registration failure path, matching the cleanup done by remove().

Fixes eb428ee0e3ca ("hwrng: ks-sa - add hw_random driver")
---
 drivers/char/hw_random/ks-sa-rng.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/char/hw_random/ks-sa-rng.c +8 -1
index 3c514b4fbc8ae..64369d4f1644c 100644
@@ -242,7 +242,14 @@ static int ks_sa_rng_probe(struct platform_device *pdev)
 		return dev_err_probe(dev, ret, "Failed to enable SA power-domain\n");
 	}
 
-	return devm_hwrng_register(&pdev->dev, &ks_sa_rng->rng);
+	ret = devm_hwrng_register(dev, &ks_sa_rng->rng);
+	if (ret) {
+		pm_runtime_put_sync(dev);
+		pm_runtime_disable(dev);
+		return ret;
+	}
+
+	return 0;
 }
 
 static void ks_sa_rng_remove(struct platform_device *pdev)
Signature · 1 line
2.53.0
author maintainer
#527 lore raw

PATCH 507/1376 xfrm6: fix out-of-bounds write in xfrm6_input_addr() when secpath is full

In reply to Greg Kroah-Hartman

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

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

From: Xiang Mei <[email protected]>

[ Upstream commit 5d9e3bf34fec9a5d237e4b7cef4a707bc2e091bc ]

The depth check in xfrm6_input_addr() is off by one:

  if (1 + sp->len == XFRM_MAX_DEPTH)
          goto drop;
  ...
  sp->xvec[sp->len++] = x;

xfrm_input() can leave sp->len == XFRM_MAX_DEPTH, and the transport-mode receive path re-enters IPv6 input via xfrm_trans_reinject() with that secpath preserved. If the inner packet carries a destination-options HAO option or a type-2 routing header, xfrm6_input_addr() is called with sp->len == XFRM_MAX_DEPTH; the check (1 + 6 == 6) is false, so sp->xvec[sp->len++] writes one slot past the 6-element xvec[]. The write stays within the sec_path allocation (invisible to KASAN); UBSAN_BOUNDS flags it and panics under panic_on_warn.

Use "sp->len >= XFRM_MAX_DEPTH", matching xfrm_input(). This also restores one chain level the old check rejected at sp->len == 5.

  UBSAN: array-index-out-of-bounds in net/ipv6/xfrm6_input.c:309:10
  index 6 is out of range for type 'xfrm_state *[6]'
Fixes 9473e1f631de ("[XFRM] MIPv6: Fix to input RO state correctly.")
Assisted-by Claude:claude-opus-4-8
---
 net/ipv6/xfrm6_input.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/ipv6/xfrm6_input.c +1 -1
index 699a001ac1662..c9e208c57a6b5 100644
@@ -249,7 +249,7 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
 		goto drop;
 	}
 
-	if (1 + sp->len == XFRM_MAX_DEPTH) {
+	if (sp->len >= XFRM_MAX_DEPTH) {
 		XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
 		goto drop;
 	}
Signature · 1 line
2.53.0
author maintainer
#528 lore raw

PATCH 508/1376 ALSA: hpi: Check transport errors during HPI6000 adapter initialization

In reply to Greg Kroah-Hartman

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

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

From: Evgenii Burenchev <[email protected]>

[ Upstream commit cc15c329663e3ef1aeed0b68e49a5d5ce4ae0d5c ]

create_adapter_obj() retrieves adapter information by calling hpi6000_message_response_sequence(). This function reports transport-level errors through its return value and DSP-reported errors via hr0.error.

The current code only checks hr0.error, causing transport-level errors to be ignored. As a result, adapter initialization may continue with an invalid response.

Check the return value of hpi6000_message_response_sequence() before examining hr0.error.

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

Fixes 719f82d3987a ("ALSA: Add support of AudioScience ASI boards")
---
 sound/pci/asihpi/hpi6000.c | 5 +++++
 1 file changed, 5 insertions(+)
sound/pci/asihpi/hpi6000.c +5 -0
index 72aa135d69f85..8aa5832f1f2a5 100644
@@ -537,6 +537,11 @@ static short create_adapter_obj(struct hpi_adapter_obj *pao,
 		hr1.size = sizeof(hr1);
 
 		error = hpi6000_message_response_sequence(pao, 0, &hm, &hr0);
+		if (error) {
+			HPI_DEBUG_LOG(ERROR, "message transport error %d\n",
+						  error);
+			return error;
+		}
 		if (hr0.error) {
 			HPI_DEBUG_LOG(DEBUG, "message error %d\n", hr0.error);
 			return hr0.error;
Signature · 1 line
2.53.0
author maintainer
#529 lore raw

PATCH 509/1376 pmdomain: bcm: bcm2835: handle genpd provider registration errors

In reply to Greg Kroah-Hartman

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

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

From: Pengpeng Hou <[email protected]>

[ Upstream commit a1d9d3b958d69a13783613304f524f489fecdd1f ]

bcm2835_power_probe() initializes all power domains and then registers the onecell genpd provider, but ignores of_genpd_add_provider_onecell() failures. Probe can therefore return success even though no provider was published.

Check the provider registration return value and jump to the existing cleanup path on failure.

Fixes 670c672608a1 ("soc: bcm: bcm2835-pm: Add support for power domains under a new binding.")
---
 drivers/pmdomain/bcm/bcm2835-power.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/pmdomain/bcm/bcm2835-power.c +6 -1
index 20130549a7a53..85406b4a99b06 100644
@@ -682,7 +682,12 @@ static int bcm2835_power_probe(struct platform_device *pdev)
 	if (ret)
 		goto fail;
 
-	of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate);
+	ret = of_genpd_add_provider_onecell(dev->parent->of_node,
+					    &power->pd_xlate);
+	if (ret) {
+		dev_err_probe(dev, ret, "failed to add genpd provider\n");
+		goto fail;
+	}
 
 	dev_info(dev, "Broadcom BCM2835 power domains driver");
 	return 0;
Signature · 1 line
2.53.0
author maintainer
#530 lore raw

PATCH 510/1376 misc: rtsx_usb: avoid USB I/O in runtime autosuspend

In reply to Greg Kroah-Hartman

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

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

From: Sean Rhodes <[email protected]>

[ Upstream commit 483c948324a3823871c004560a92545759d3253c ]

The runtime autosuspend callback currently queries card status and clears OCP by issuing USB register accesses. This can run from the USB runtime-PM path itself, which is the wrong place to start more device I/O.

Keep a cached copy of the card-status bits from normal status reads instead. During runtime autosuspend, use that cached value only to preserve the existing Memory Stick autosuspend deferral.

Do not treat raw SD_CD as an autosuspend blocker, because tray-based SD readers can assert SD_CD with an empty tray. A real SD card is protected by the SD/MMC child runtime-PM usage once powered.

Also stop clearing OCP from the runtime autosuspend callback, so the callback does not issue USB commands.

Fixes bb400d2120bd ("mfd: rtsx_usb: Defer autosuspend while card exists")
---
 drivers/misc/cardreader/rtsx_usb.c | 23 ++++++++++++++++++++---
 include/linux/rtsx_usb.h           |  3 +++
 2 files changed, 23 insertions(+), 3 deletions(-)
drivers/misc/cardreader/rtsx_usb.c +20 -3
index f546b050cb495..0a585be7f0860 100644
@@ -312,6 +312,9 @@ int rtsx_usb_get_card_status(struct rtsx_ucr *ucr, u16 *status)
 	if (ret < 0)
 		return ret;
 
+	ucr->card_status_cache = *status;
+	ucr->card_status_valid = true;
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(rtsx_usb_get_card_status);
@@ -619,6 +622,7 @@ static int rtsx_usb_probe(struct usb_interface *intf,
 {
 	struct usb_device *usb_dev = interface_to_usbdev(intf);
 	struct rtsx_ucr *ucr;
+	u16 status;
 	int ret;
 
 	dev_dbg(&intf->dev,
@@ -655,6 +659,9 @@ static int rtsx_usb_probe(struct usb_interface *intf,
 	if (ret)
 		goto out_init_fail;
 
+	/* Prime cached status for runtime autosuspend decisions. */
+	rtsx_usb_get_card_status(ucr, &status);
+
 	/* initialize USB SG transfer timer */
 	timer_setup(&ucr->sg_timer, rtsx_usb_sg_timed_out, 0);
 
@@ -709,17 +716,27 @@ static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message)
 	struct rtsx_ucr *ucr =
 		(struct rtsx_ucr *)usb_get_intfdata(intf);
 	u16 val = 0;
+	bool valid = false;
 
 	dev_dbg(&intf->dev, "%s called with pm message 0x%04x\n",
 			__func__, message.event);
 
 	if (PMSG_IS_AUTO(message)) {
 		if (mutex_trylock(&ucr->dev_mutex)) {
-			rtsx_usb_get_card_status(ucr, &val);
+			valid = ucr->card_status_valid;
+			if (valid)
+				val = ucr->card_status_cache;
 			mutex_unlock(&ucr->dev_mutex);
 
-			/* Defer the autosuspend if card exists */
-			if (val & (SD_CD | MS_CD)) {
+			/*
+			 * Do not issue USB commands from runtime autosuspend.
+			 * Raw SD_CD is not authoritative on tray-based readers,
+			 * while a real SD card is protected by the SD/MMC child
+			 * runtime-PM reference once the card is powered. Keep
+			 * the historical Memory Stick autosuspend deferral when
+			 * the cached status says MS media is present.
+			 */
+			if (valid && (val & MS_CD)) {
 				device_for_each_child(&intf->dev, NULL, rtsx_usb_resume_child);
 				return -EAGAIN;
 			}
include/linux/rtsx_usb.h +3 -0
index 3247ed8e9ff0f..5933751cf7219 100644
@@ -57,6 +57,9 @@ struct rtsx_ucr {
 
 	struct timer_list	sg_timer;
 	struct mutex		dev_mutex;
+
+	u16			card_status_cache;
+	bool			card_status_valid;
 };
 
 /* buffer size */
Signature · 1 line
2.53.0
author maintainer
#531 lore raw

PATCH 511/1376 RDMA/hfi1: Preserve unit 0 on allocation failure

In reply to Greg Kroah-Hartman

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

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

From: Leon Romanovsky <[email protected]>

[ Upstream commit 2e3809ad8911f5d5581b3f046bd628417bface76 ]

hfi1_free_devdata() assumes that the device was inserted into the unit table and unconditionally erases dd->unit. If xa_alloc_irq() fails, the zero-initialized unit remains zero, so full cleanup can remove an unrelated device from index 0.

Release only the rdmavt allocation and return immediately while the unit table has not acquired the device.

Fixes 03b92789e5cf ("hfi1: Convert hfi1_unit_table to XArray")
---
 drivers/infiniband/hw/hfi1/init.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/infiniband/hw/hfi1/init.c +3 -2
index cbac4a442d9ec..e84616bc4fa99 100644
@@ -1227,8 +1227,9 @@ static struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev,
 			GFP_KERNEL);
 	if (ret < 0) {
 		dev_err(&pdev->dev,
-			"Could not allocate unit ID: error %d\n", -ret);
-		goto bail;
+			"Could not allocate unit ID: error %pe\n", ERR_PTR(ret));
+		rvt_dealloc_device(&dd->verbs_dev.rdi);
+		return ERR_PTR(ret);
 	}
 	rvt_set_ibdev_name(&dd->verbs_dev.rdi, "%s_%d", class_name(), dd->unit);
 	/*
Signature · 1 line
2.53.0
author maintainer
#532 lore raw

PATCH 512/1376 RDMA/hfi1: Free RX data on late probe failure

In reply to Greg Kroah-Hartman

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

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

From: Leon Romanovsky <[email protected]>

[ Upstream commit 8e17e101e04a3dc062e2719da57ff78c1c060632 ]

hfi1_init_dd() allocates the shared AIP/VNIC RX support before returning. If hfi1_init() or hfi1_register_ib_device() later fails, init_one() tears down the device data without calling hfi1_free_rx(). This leaks netdev_rx and its dummy netdev.

Free the RX support after IB unregistration and before postinit_cleanup(), as done on normal device removal.

Fixes 4730f4a6c6b2 ("IB/hfi1: Activate the dummy netdev")
---
 drivers/infiniband/hw/hfi1/init.c | 1 +
 1 file changed, 1 insertion(+)
drivers/infiniband/hw/hfi1/init.c +1 -0
index e84616bc4fa99..d6331f90222d8 100644
@@ -1678,6 +1678,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 			hfi1_device_remove(dd);
 		if (!ret)
 			hfi1_unregister_ib_device(dd);
+		hfi1_free_rx(dd);
 		postinit_cleanup(dd);
 		if (initfail)
 			ret = initfail;
Signature · 1 line
2.53.0
author maintainer
#533 lore raw

PATCH 513/1376 RDMA/hfi1: Remove redundant PCI device ID validation

In reply to Greg Kroah-Hartman

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

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

From: Leon Romanovsky <[email protected]>

[ Upstream commit af9117d02f50514c998714b23820de71d0aa5d24 ]

The PCI core calls init_one() only after pci_match_device() has selected an ID. For normal probing, hfi1_pci_tbl already restricts matches to the two supported Intel device IDs. Dynamic IDs and driver_override are explicit requests to attempt binding, so the probe should not second-guess the PCI core's decision.

Remove the redundant check.

Stable-dep-of: 9f674ba674a0 ("RDMA/hfi1: Allocate device data after PCI initialization")

---
 drivers/infiniband/hw/hfi1/init.c | 9 ---------
 1 file changed, 9 deletions(-)
drivers/infiniband/hw/hfi1/init.c +0 -9
index d6331f90222d8..fc6c01d64050e 100644
@@ -1563,15 +1563,6 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	/* First, lock the non-writable module parameters */
 	HFI1_CAP_LOCK();
 
-	/* Validate dev ids */
-	if (!(ent->device == PCI_DEVICE_ID_INTEL0 ||
-	      ent->device == PCI_DEVICE_ID_INTEL1)) {
-		dev_err(&pdev->dev, "Failing on unknown Intel deviceid 0x%x\n",
-			ent->device);
-		ret = -ENODEV;
-		goto bail;
-	}
-
 	/* Allocate the dd so we can get to work */
 	dd = hfi1_alloc_devdata(pdev, NUM_IB_PORTS *
 				sizeof(struct hfi1_pportdata));
Signature · 1 line
2.53.0
author maintainer
#534 lore raw

PATCH 514/1376 RDMA/hfi1: Create workqueues before device initialization

In reply to Greg Kroah-Hartman

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

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

From: Leon Romanovsky <[email protected]>

[ Upstream commit 0d5618c1b2fc9dd4fc086f0226acd8a077ab6c1b ]

create_workqueues() only needs fields set up by hfi1_alloc_devdata(). Call it before hfi1_init_dd() so a workqueue allocation failure happens before chip resources are initialized.

To keep the reordered error paths safe, make init_one() own hfi1_devdata. hfi1_init_dd() unwinds its partial setup but leaves the allocation for the caller to free. If device initialization fails, destroy the workqueues before freeing the device data.

Stable-dep-of: 9f674ba674a0 ("RDMA/hfi1: Allocate device data after PCI initialization")

---
 drivers/infiniband/hw/hfi1/chip.c |  4 +---
 drivers/infiniband/hw/hfi1/hfi.h  |  2 --
 drivers/infiniband/hw/hfi1/init.c | 19 ++++++++++---------
 3 files changed, 11 insertions(+), 14 deletions(-)
drivers/infiniband/hw/hfi1/chip.c +1 -3
index c52e6b2c9914d..db96a7547fb7c 100644
@@ -15065,7 +15065,7 @@ int hfi1_init_dd(struct hfi1_devdata *dd)
 	 */
 	ret = hfi1_pcie_ddinit(dd, pdev);
 	if (ret < 0)
-		goto bail_free;
+		goto bail;
 
 	/* Save PCI space registers to rewrite after device reset */
 	ret = save_pci_variables(dd);
@@ -15320,8 +15320,6 @@ int hfi1_init_dd(struct hfi1_devdata *dd)
 bail_cleanup:
 	hfi1_free_rx(dd);
 	hfi1_pcie_ddcleanup(dd);
-bail_free:
-	hfi1_free_devdata(dd);
 bail:
 	return ret;
 }
drivers/infiniband/hw/hfi1/hfi.h +0 -2
index eb38f81aeeb1e..67df5c65c6e51 100644
@@ -2044,9 +2044,7 @@ struct cc_state *get_cc_state_protected(struct hfi1_pportdata *ppd)
 		/* waiting for an urgent packet to arrive */
 #define HFI1_CTXT_WAITING_URG 4
 
-/* free up any allocated data at closes */
 int hfi1_init_dd(struct hfi1_devdata *dd);
-void hfi1_free_devdata(struct hfi1_devdata *dd);
 
 /* LED beaconing functions */
 void hfi1_start_led_override(struct hfi1_pportdata *ppd, unsigned int timeon,
drivers/infiniband/hw/hfi1/init.c +10 -9
index fc6c01d64050e..904a426115c54 100644
@@ -630,8 +630,6 @@ void hfi1_init_pportdata(struct pci_dev *pdev, struct hfi1_pportdata *ppd,
 	ppd->sm_trap_qp = 0x0;
 	ppd->sa_qp = 0x1;
 
-	ppd->hfi1_wq = NULL;
-
 	spin_lock_init(&ppd->cca_timer_lock);
 
 	for (i = 0; i < OPA_MAX_SLS; i++) {
@@ -1164,7 +1162,7 @@ static void finalize_asic_data(struct hfi1_devdata *dd,
  * It cleans up and frees all data structures set up by
  * by hfi1_alloc_devdata().
  */
-void hfi1_free_devdata(struct hfi1_devdata *dd)
+static void hfi1_free_devdata(struct hfi1_devdata *dd)
 {
 	struct hfi1_asic_data *ad;
 	unsigned long flags;
@@ -1616,17 +1614,17 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	if (ret)
 		goto bail;
 
+	ret = create_workqueues(dd);
+	if (ret)
+		goto free_devdata;
+
 	/*
 	 * Do device-specific initialization, function table setup, dd
 	 * allocation, etc.
 	 */
 	ret = hfi1_init_dd(dd);
 	if (ret)
-		goto clean_bail; /* error already printed */
-
-	ret = create_workqueues(dd);
-	if (ret)
-		goto clean_bail;
+		goto destroy_workqueues; /* error already printed */
 
 	/* do the generic initialization */
 	initfail = hfi1_init(dd, 0);
@@ -1680,7 +1678,10 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	return 0;
 
-clean_bail:
+destroy_workqueues:
+	destroy_workqueues(dd);
+free_devdata:
+	hfi1_free_devdata(dd);
 	hfi1_pcie_cleanup(pdev);
 bail:
 	return ret;
Signature · 1 line
2.53.0
author maintainer
#535 lore raw

PATCH 515/1376 RDMA/hfi1: Stop flushing the global IB workqueue

In reply to Greg Kroah-Hartman

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

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

From: Leon Romanovsky <[email protected]>

[ Upstream commit d43b1c17f9e1b9d34a0d742f569c00d84147ebc0 ]

hfi1 does not queue work on ib_wq. QSFP and link work run on the per-port link_wq, while the remaining device work uses hfi1_wq or dedicated queues. The probe failure path destroys both per-port workqueues, and normal device removal flushes them in shutdown_device() before destroying them.

Remove the flushes of the core-owned global workqueue. Waiting for unrelated core or other device work is not part of hfi1 teardown.

Fixes 71d47008ca1b ("IB/hfi1: Create workqueue for link events")
---
 drivers/infiniband/hw/hfi1/init.c | 4 ----
 1 file changed, 4 deletions(-)
drivers/infiniband/hw/hfi1/init.c +0 -4
index 904a426115c54..d6846d77f9479 100644
@@ -1650,7 +1650,6 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	if (initfail || ret) {
 		msix_clean_up_interrupts(dd);
 		stop_timers(dd);
-		flush_workqueue(ib_wq);
 		for (pidx = 0; pidx < dd->num_pports; ++pidx) {
 			hfi1_quiet_serdes(dd->pport + pidx);
 			ppd = dd->pport + pidx;
@@ -1727,9 +1726,6 @@ static void remove_one(struct pci_dev *pdev)
 
 	stop_timers(dd);
 
-	/* wait until all of our (qsfp) queue_work() calls complete */
-	flush_workqueue(ib_wq);
-
 	postinit_cleanup(dd);
 }
 
Signature · 1 line
2.53.0
author maintainer
#536 lore raw

PATCH 516/1376 RDMA/hfi1: Initialize debugfs after probe completes

In reply to Greg Kroah-Hartman

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

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

From: Leon Romanovsky <[email protected]>

[ Upstream commit bb18740b302f6f222ce3d5a7e5c45a52a90df805 ]

Commit ed6f653fe430 ("staging/rdma/hfi1: Fix debugfs access race") moved debugfs creation after device initialization and IB registration so users cannot access the files before the driver is ready. However, init_one() still creates them before character device creation and SDMA startup finish.

Move hfi1_dbg_ibdev_init() to the end of the successful probe path, matching hfi1_dbg_ibdev_exit() as the first action in remove_one().

Fixes ed6f653fe430 ("staging/rdma/hfi1: Fix debugfs access race")
---
 drivers/infiniband/hw/hfi1/init.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/infiniband/hw/hfi1/init.c +2 -4
index d6846d77f9479..c862ae679c9ca 100644
@@ -1637,11 +1637,8 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	 * we still create devices, so diags, etc. can be used
 	 * to determine cause of problem.
 	 */
-	if (!initfail && !ret) {
+	if (!initfail && !ret)
 		dd->flags |= HFI1_INITTED;
-		/* create debufs files after init and ib register */
-		hfi1_dbg_ibdev_init(&dd->verbs_dev);
-	}
 
 	j = hfi1_device_create(dd);
 	if (j)
@@ -1674,6 +1671,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	}
 
 	sdma_start(dd);
+	hfi1_dbg_ibdev_init(&dd->verbs_dev);
 
 	return 0;
 
Signature · 1 line
2.53.0
author maintainer
#537 lore raw

PATCH 517/1376 ASoC: apple: mca: increase SERDES reset delay

In reply to Greg Kroah-Hartman

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

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

From: James Calligeros <[email protected]>

[ Upstream commit cccd721e5aab03e92234faee72b363c9ba60611c ]

The SERDES clusters in this peripheral take a long time to warm up. We tried polling the reset bit until cleared, however this is not a reliable signal of readiness to be configured. Only waiting ~25 us to give the cluster a chance to settle makes it work reliably.

Increase the 2 us delay to 25 us and hope we never have to do this again.

Fixes d8b3e396088d ("ASoC: apple: mca: Fix SERDES reset sequence")
---
 sound/soc/apple/mca.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
sound/soc/apple/mca.c +3 -3
index 4a4ec1c09e132..d89e57414a5da 100644
@@ -210,10 +210,10 @@ static void mca_fe_early_trigger(struct snd_pcm_substream *substream, int cmd,
 			   SERDES_STATUS_EN | SERDES_STATUS_RST,
 			   SERDES_STATUS_RST);
 		/*
-		 * Experiments suggest that it takes at most ~1 us
-		 * for the bit to clear, so wait 2 us for good measure.
+		 * The SERDES cluster needs a bit of time to reset itself
+		 * and settle before we start poking it. This is... slow...
 		 */
-		udelay(2);
+		udelay(25);
 		WARN_ON(readl_relaxed(cl->base + serdes_unit + REG_SERDES_STATUS) &
 			SERDES_STATUS_RST);
 		mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,
Signature · 1 line
2.53.0
author maintainer
#538 lore raw

PATCH 518/1376 isofs: fix out-of-bounds page array access on empty zisofs block

In reply to Greg Kroah-Hartman

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

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

From: Xiang Mei <[email protected]>

[ Upstream commit 68d4d3e78150c7ed7d1195af63ad1e6ace30c661 ]

zisofs_uncompress_block()'s empty-block fast path returns pcount << PAGE_SHIFT, ignoring the incoming poffset, unlike the decompression path which returns bytes produced relative to poffset. zisofs_fill_pages() uses that return to advance its page cursor, so when the zisofs block size is below PAGE_SIZE and a sub-page block leaves poffset partway into a page, a following empty block over-counts and advances pages[] one element past its end, after which
"if (poffset && *pages)" reads pages[1] out of bounds. rock.c only rejects a block-size shift > 17, so a crafted "ZF" Rock Ridge record can set it below PAGE_SHIFT; the bug is reached by an ordinary read() of a compressed file on such a mounted ISO9660 image.

Return the byte count relative to poffset and zero only [poffset, PAGE_SIZE) of the first page, matching the decompression path. The page-aligned case (poffset == 0) is unaffected.

  BUG: KASAN: slab-out-of-bounds in zisofs_read_folio (fs/isofs/compress.c:290)
  Read of size 8 at addr ffff88800f5eac48 by task exploit/142
   zisofs_read_folio (fs/isofs/compress.c:290)
   read_pages (mm/readahead.c:184)
   ...
   filemap_read (mm/filemap.c:2814)
   vfs_read (fs/read_write.c:574)
   __x64_sys_pread64 (fs/read_write.c:769)
   do_syscall_64 (arch/x86/entry/syscall_64.c:94)
   entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
  The buggy address is located 0 bytes to the right of the
  allocated 8-byte region in the kmalloc-8 cache
Fixes 59bc055211b8 ("zisofs: Implement reading of compressed files when PAGE_CACHE_SIZE > compress block size")
Assisted-by Claude:claude-opus-4-8
---
 fs/isofs/compress.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
fs/isofs/compress.c +4 -2
index 34d5baa5d88a0..05b9fa80ba9c2 100644
@@ -65,12 +65,14 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
 	/* Empty block? */
 	if (block_size == 0) {
 		for ( i = 0 ; i < pcount ; i++ ) {
+			unsigned int off = i ? 0 : poffset;
+
 			if (!pages[i])
 				continue;
-			memzero_page(pages[i], 0, PAGE_SIZE);
+			memzero_page(pages[i], off, PAGE_SIZE - off);
 			SetPageUptodate(pages[i]);
 		}
-		return ((loff_t)pcount) << PAGE_SHIFT;
+		return (((loff_t)pcount) << PAGE_SHIFT) - poffset;
 	}
 
 	/* Because zlib is not thread-safe, do all the I/O at the top. */
Signature · 1 line
2.53.0
author maintainer
#539 lore raw

PATCH 519/1376 iommufd/selftest: Avoid selftest dirty bitmap size wrap

In reply to Greg Kroah-Hartman

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

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

From: Samuel Moelius <[email protected]>

[ Upstream commit 4132ba2ae2cf14c289e3fabc1c95ac244d643356 ]

IOMMU_TEST_OP_DIRTY sizes its temporary dirty bitmap from length / page_size. Very large selftest ranges can make the DIV_ROUND_UP() additions wrap before allocation, producing a zero-length allocation while the later test_bit() loop still walks the original number of bits.

The selftest helper does not need to support unbounded dirty bitmap sizes. Reject requests that would allocate more than SZ_16M for the temporary buffer.

Fixes 79ea4a496ab5 ("iommufd/selftest: Fix buffer read overrrun in the dirty test")
Assisted-by Codex:gpt-5.5-cyber-preview
---
 drivers/iommu/iommufd/selftest.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/iommu/iommufd/selftest.c +4 -1
index aed260d4a93cc..8ec251acd9238 100644
@@ -10,6 +10,7 @@
 #include <linux/iommu.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/sizes.h>
 #include <linux/xarray.h>
 #include <uapi/linux/iommufd.h>
 
@@ -1359,6 +1360,9 @@ static int iommufd_test_dirty(struct iommufd_ucmd *ucmd, unsigned int mockpt_id,
 	if (!page_size || !length || iova % page_size || length % page_size ||
 	    !uptr)
 		return -EINVAL;
+	max = length / page_size;
+	if (max > SZ_16M * BITS_PER_BYTE)
+		return -EOVERFLOW;
 
 	hwpt = get_md_pagetable(ucmd, mockpt_id, &mock);
 	if (IS_ERR(hwpt))
@@ -1369,7 +1373,6 @@ static int iommufd_test_dirty(struct iommufd_ucmd *ucmd, unsigned int mockpt_id,
 		goto out_put;
 	}
 
-	max = length / page_size;
 	tmp = kvzalloc(DIV_ROUND_UP(max, BITS_PER_LONG) * sizeof(unsigned long),
 		       GFP_KERNEL_ACCOUNT);
 	if (!tmp) {
Signature · 1 line
2.53.0
author maintainer
#540 lore raw

PATCH 520/1376 media: v4l2-async: Unregister sub-device if asc_list is empty

In reply to Greg Kroah-Hartman

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

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

From: Hans Verkuil <[email protected]>

[ Upstream commit 4e72f13d58c4245c177a9d5f54579345554f354d ]

When my em28xx USB device that uses the i2c tvp5150 driver is disconnected, it crashes.

The cause is that the tvp5150 i2c module uses v4l2_async, but the em28xx driver does not since it predates v4l2_async.

In that corner case sd->asc_list is empty, so v4l2_async_unregister_subdev() never calls v4l2_device_unregister_subdev().

Modify the code so that, if sd->asc_list is empty, v4l2_device_unregister_subdev() is still called.

Fixes 28a1295795d8 ("media: v4l: async: Allow multiple connections between entities")
---
 drivers/media/v4l2-core/v4l2-async.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/media/v4l2-core/v4l2-async.c +12 -3
index 70284f50e1f93..5f6685e34d90f 100644
@@ -897,9 +897,18 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
 	sd->subdev_notifier = NULL;
 
 	if (sd->asc_list.next) {
-		list_for_each_entry_safe(asc, asc_tmp, &sd->asc_list,
-					 asc_subdev_entry) {
-			v4l2_async_unbind_subdev_one(asc->notifier, asc);
+		if (list_empty(&sd->asc_list)) {
+			/*
+			 * If the sub-device was registered through other means
+			 * than v4l2-async, there are no async connections but
+			 * the sub-device may still well be registered.
+			 * Unregister it now.
+			 */
+			v4l2_device_unregister_subdev(sd);
+		} else {
+			list_for_each_entry_safe(asc, asc_tmp, &sd->asc_list,
+						 asc_subdev_entry)
+				v4l2_async_unbind_subdev_one(asc->notifier, asc);
 		}
 	}
 
Signature · 1 line
2.53.0
author maintainer
#541 lore raw

PATCH 521/1376 rpmsg: glink: remove duplicate code for rpmsg device remove

In reply to Greg Kroah-Hartman

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

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

From: Srinivas Kandagatla <[email protected]>

[ Upstream commit 112766cdf2e5ea0a0f72b0304d57a6f74c066670 ]

rpmsg device remove code is duplicated in at-least 2-3 places, add a helper function to remove this duplicated code.

Stable-dep-of: 5a5a48e788e0 ("rpmsg: glink: fix deadlock in endpoint destroy during driver detach")

---
 drivers/rpmsg/qcom_glink_native.c | 43 ++++++++++++-------------------
 1 file changed, 16 insertions(+), 27 deletions(-)
drivers/rpmsg/qcom_glink_native.c +16 -27
index c2d39a3bcea7e..9d4fee6409423 100644
@@ -1395,11 +1395,23 @@ static int qcom_glink_announce_create(struct rpmsg_device *rpdev)
 	return 0;
 }
 
+static void qcom_glink_remove_rpmsg_device(struct qcom_glink *glink, struct glink_channel *channel)
+{
+	struct rpmsg_channel_info chinfo;
+
+	if (channel->rpdev) {
+		strscpy_pad(chinfo.name, channel->name, sizeof(chinfo.name));
+		chinfo.src = RPMSG_ADDR_ANY;
+		chinfo.dst = RPMSG_ADDR_ANY;
+		rpmsg_unregister_device(glink->dev, &chinfo);
+	}
+	channel->rpdev = NULL;
+}
+
 static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept)
 {
 	struct glink_channel *channel = to_glink_channel(ept);
 	struct qcom_glink *glink = channel->glink;
-	struct rpmsg_channel_info chinfo;
 	unsigned long flags;
 
 	spin_lock_irqsave(&channel->recv_lock, flags);
@@ -1407,14 +1419,7 @@ static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept)
 	spin_unlock_irqrestore(&channel->recv_lock, flags);
 
 	/* Decouple the potential rpdev from the channel */
-	if (channel->rpdev) {
-		strscpy_pad(chinfo.name, channel->name, sizeof(chinfo.name));
-		chinfo.src = RPMSG_ADDR_ANY;
-		chinfo.dst = RPMSG_ADDR_ANY;
-
-		rpmsg_unregister_device(glink->dev, &chinfo);
-	}
-	channel->rpdev = NULL;
+	qcom_glink_remove_rpmsg_device(glink, channel);
 
 	qcom_glink_send_close_req(glink, channel);
 }
@@ -1704,7 +1709,6 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
 
 static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
 {
-	struct rpmsg_channel_info chinfo;
 	struct glink_channel *channel;
 	unsigned long flags;
 
@@ -1720,14 +1724,7 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
 	/* cancel pending rx_done work */
 	cancel_work_sync(&channel->intent_work);
 
-	if (channel->rpdev) {
-		strscpy_pad(chinfo.name, channel->name, sizeof(chinfo.name));
-		chinfo.src = RPMSG_ADDR_ANY;
-		chinfo.dst = RPMSG_ADDR_ANY;
-
-		rpmsg_unregister_device(glink->dev, &chinfo);
-	}
-	channel->rpdev = NULL;
+	qcom_glink_remove_rpmsg_device(glink, channel);
 
 	qcom_glink_send_close_ack(glink, channel);
 
@@ -1741,7 +1738,6 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
 
 static void qcom_glink_rx_close_ack(struct qcom_glink *glink, unsigned int lcid)
 {
-	struct rpmsg_channel_info chinfo;
 	struct glink_channel *channel;
 	unsigned long flags;
 
@@ -1763,14 +1759,7 @@ static void qcom_glink_rx_close_ack(struct qcom_glink *glink, unsigned int lcid)
 	spin_unlock_irqrestore(&glink->idr_lock, flags);
 
 	/* Decouple the potential rpdev from the channel */
-	if (channel->rpdev) {
-		strscpy(chinfo.name, channel->name, sizeof(chinfo.name));
-		chinfo.src = RPMSG_ADDR_ANY;
-		chinfo.dst = RPMSG_ADDR_ANY;
-
-		rpmsg_unregister_device(glink->dev, &chinfo);
-	}
-	channel->rpdev = NULL;
+	qcom_glink_remove_rpmsg_device(glink, channel);
 
 	kref_put(&channel->refcount, qcom_glink_channel_release);
 }
Signature · 1 line
2.53.0
author maintainer
#542 lore raw

PATCH 522/1376 rpmsg: glink: fix deadlock in endpoint destroy during driver detach

In reply to Greg Kroah-Hartman

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

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

From: Vishnu Santhosh <[email protected]>

[ Upstream commit 5a5a48e788e02fd8a8eb7188ce440572d6c12418 ]

During driver detach, the device core holds the device mutex throughout the driver's remove callback chain. When the rpmsg endpoint is destroyed as part of that teardown, the GLINK endpoint destroy implementation attempts to unregister the underlying rpmsg device. That unregistration calls device_del(), which tries to re-acquire the same device mutex already held higher up the stack, causing rmmod to hang indefinitely.

The deadlock manifests with the following call chain:

[<0>] device_del+0x44/0x414  <- tries to acquire same mutex
[<0>] device_unregister+0x18/0x34
[<0>] rpmsg_unregister_device+0x28/0x4c
[<0>] qcom_glink_remove_rpmsg_device+0x70/0xc0
[<0>] qcom_glink_destroy_ept+0x58/0xbc
[<0>] rpmsg_dev_remove+0x50/0x60
[<0>] device_remove+0x4c/0x80
[<0>] device_release_driver_internal+0x1cc/0x228  <- acquires device mutex
[<0>] driver_detach+0x4c/0x98
[<0>] bus_remove_driver+0x6c/0xbc
[<0>] driver_unregister+0x30/0x60
[<0>] unregister_rpmsg_driver+0x10/0x1c
[<0>] fastrpc_exit+0x28/0x38 [fastrpc]
[<0>] __arm64_sys_delete_module+0x1b8/0x294
[<0>] invoke_syscall+0x48/0x10c
[<0>] el0_svc_common.constprop.0+0xc0/0xe0
[<0>] do_el0_svc+0x1c/0x28
[<0>] el0_svc+0x34/0x108
[<0>] el0t_64_sync_handler+0xa0/0xe4
[<0>] el0t_64_sync+0x198/0x19c

The rpmsg device unregistration inside endpoint destroy is redundant. In both contexts where endpoint destruction is triggered:

- Driver detach path: the driver core already tears down the rpmsg device.

- Channel close path: the rpmsg device is already unregistered before endpoint destruction is reached.

Remove the redundant unregistration to fix the deadlock.

---
 drivers/rpmsg/qcom_glink_native.c | 3 ---
 1 file changed, 3 deletions(-)
drivers/rpmsg/qcom_glink_native.c +0 -3
index 9d4fee6409423..c21a5e4da0f68 100644
@@ -1418,9 +1418,6 @@ static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept)
 	channel->ept.cb = NULL;
 	spin_unlock_irqrestore(&channel->recv_lock, flags);
 
-	/* Decouple the potential rpdev from the channel */
-	qcom_glink_remove_rpmsg_device(glink, channel);
-
 	qcom_glink_send_close_req(glink, channel);
 }
 
Signature · 1 line
2.53.0
author maintainer
#543 lore raw

PATCH 523/1376 cxl/memdev: Fix firmware upload exact-fit handling

In reply to Greg Kroah-Hartman

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

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

From: Guzebing <[email protected]>

[ Upstream commit af5035e1b3e400067bb003975936e5407377e7a3 ]

cxl_fw_prepare() classifies a firmware image as a one-shot transfer only when its Transfer FW input payload is smaller than the mailbox payload size. An image that exactly fills the payload is therefore treated as a multi-part transfer.

The firmware loader invokes cxl_fw_write() only once for that image. Since both offset == 0 and remaining == 0, the multi-part action selection sends INITIATE, never sends END, and then attempts to activate the target slot.

Include equality in the one-shot classification so exact-fit images use the FULL action.

Fixes 9521875bbe00 ("cxl: add a firmware update mechanism using the sysfs firmware loader")
---
 drivers/cxl/core/memdev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/cxl/core/memdev.c +1 -1
index 4d544a55ac3e8..d2a554c2f92b0 100644
@@ -845,7 +845,7 @@ static enum fw_upload_err cxl_fw_prepare(struct fw_upload *fwl, const u8 *data,
 	if (!size)
 		return FW_UPLOAD_ERR_INVALID_SIZE;
 
-	mds->fw.oneshot = struct_size(transfer, data, size) <
+	mds->fw.oneshot = struct_size(transfer, data, size) <=
 			    cxl_mbox->payload_size;
 
 	if (cxl_mem_get_fw_info(mds))
Signature · 1 line
2.53.0
author maintainer
#544 lore raw

PATCH 524/1376 cxl/mbox: Break poison list loop on an empty payload

In reply to Greg Kroah-Hartman

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

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

From: Dave Jiang <[email protected]>

[ Upstream commit 8b301c4afbce4bc3f94528441d8d5ce1366504ad ]

A device that returns count == 0 with CXL_POISON_FLAG_MORE set on every iteration never advances nr_records, so the max_errors guard never trips and the do/while loops forever while holding poison.mutex. That hangs the sysfs-triggered scan thread and blocks all subsequent poison operations on the device. The existing "Protect against an uncleared _FLAG_MORE" guard was intended to bound a misbehaving device but does not cover the count == 0 case.

Stop the loop on an empty payload so a malfunctioning or malicious device cannot wedge the poison scan.

Fixes ed83f7ca398b ("cxl/mbox: Add GET_POISON_LIST mailbox command")
Assisted-by Claude:claude-opus-4-8
---
 drivers/cxl/core/mbox.c | 5 +++++
 1 file changed, 5 insertions(+)
drivers/cxl/core/mbox.c +5 -0
index 9b178abd1528e..b094aac78ca15 100644
@@ -1358,6 +1358,11 @@ int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len,
 		if (rc)
 			break;
 
+		if (!le16_to_cpu(po->count)) {
+			dev_dbg(&cxlmd->dev, "Poison empty payload!\n");
+			break;
+		}
+
 		for (int i = 0; i < le16_to_cpu(po->count); i++)
 			trace_cxl_poison(cxlmd, cxlr, &po->record[i],
 					 po->flags, po->overflow_ts,
Signature · 1 line
2.53.0
author maintainer
#545 lore raw

PATCH 525/1376 cxl/pci: Honor -EPROBE_DEFER from component register setup

In reply to Greg Kroah-Hartman

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

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

From: Dave Jiang <[email protected]>

[ Upstream commit 430c502c80e542e77bcf97db13ec0e8cdf9addb0 ]

cxl_pci_setup_regs() for CXL_REGLOC_RBI_COMPONENT can return -EPROBE_DEFER on a Restricted CXL Host (RCD) when the upstream port has not yet been enumerated and the Component Registers must be extracted from the RCRB. cxl_pci_probe() treats every non-zero return from that call as the benign "component registers not found" case, logs a warning, and continues. The rc is then immediately overwritten by the subsequent cxl_pci_type3_init_mailbox() call, so the deferral is silently swallowed.

Return -EPROBE_DEFER instead of continuing so the probe is retried once the upstream port is available.

---
 drivers/cxl/pci.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/cxl/pci.c +5 -2
index 02040b51f44ec..82cbacb3e2ca1 100644
@@ -851,10 +851,13 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	 */
 	rc = cxl_pci_setup_regs(pdev, CXL_REGLOC_RBI_COMPONENT,
 				&cxlds->reg_map);
-	if (rc)
+	if (rc) {
+		if (rc == -EPROBE_DEFER)
+			return rc;
 		dev_warn(&pdev->dev, "No component registers (%d)\n", rc);
-	else if (!cxlds->reg_map.component_map.ras.valid)
+	} else if (!cxlds->reg_map.component_map.ras.valid) {
 		dev_dbg(&pdev->dev, "RAS registers not found\n");
+	}
 
 	rc = cxl_map_component_regs(&cxlds->reg_map, &cxlds->regs.component,
 				    BIT(CXL_CM_CAP_CAP_ID_RAS));
Signature · 1 line
2.53.0
author maintainer
#546 lore raw

PATCH 526/1376 fs/ntfs3: Add more checks in mi_enum_attr (part 2)

In reply to Greg Kroah-Hartman

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

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

From: Konstantin Komarov <[email protected]>

[ Upstream commit a8f659ce14f8f734894227ba2c5ca78c8451501e ]

Add offset check before access to attr->non_res field as mentioned in [1].

[1] https://lore.kernel.org/ntfs3/[email protected]/

Stable-dep-of: 7c4841e2a627 ("fs/ntfs3: fix slab-out-of-bounds write in ni_create_attr_list()")

---
 fs/ntfs3/record.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)
fs/ntfs3/record.c +13 -3
index f810f0419d25e..61d53d39f3b9f 100644
@@ -212,7 +212,7 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
 			return NULL;
 
 		if (off >= used || off < MFTRECORD_FIXUP_OFFSET_1 ||
-		    !IS_ALIGNED(off, 4)) {
+		    !IS_ALIGNED(off, 8)) {
 			return NULL;
 		}
 
@@ -236,8 +236,11 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
 		off += asize;
 	}
 
-	/* Can we use the first field (attr->type). */
-	/* NOTE: this code also checks attr->size availability. */
+	/*
+	 * Can we use the first fields:
+	 * attr->type,
+	 * attr->size
+	 */
 	if (off + 8 > used) {
 		static_assert(ALIGN(sizeof(enum ATTR_TYPE), 8) == 8);
 		return NULL;
@@ -259,10 +262,17 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
 
 	asize = le32_to_cpu(attr->size);
 
+	if (!IS_ALIGNED(asize, 8))
+		return NULL;
+
 	/* Check overflow and boundary. */
 	if (off + asize < off || off + asize > used)
 		return NULL;
 
+	/* Can we use the field attr->non_res. */
+	if (off + 9 > used)
+		return NULL;
+
 	/* Check size of attribute. */
 	if (!attr->non_res) {
 		/* Check resident fields. */
Signature · 1 line
2.53.0
author maintainer
#547 lore raw

PATCH 527/1376 fs/ntfs3: Mark inode as bad as soon as error detected in mi_enum_attr()

In reply to Greg Kroah-Hartman

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

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

From: Konstantin Komarov <[email protected]>

[ Upstream commit 2afd4d267e6dbaec8d3ccd4f5396cb84bc67aa2e ]

Extended the mi_enum_attr() function interface with an additional parameter, struct ntfs_inode *ni, to allow marking the inode as bad as soon as an error is detected.

Stable-dep-of: 7c4841e2a627 ("fs/ntfs3: fix slab-out-of-bounds write in ni_create_attr_list()")

---
 fs/ntfs3/attrib.c  | 11 ++++---
 fs/ntfs3/frecord.c | 59 ++++++++++++++++++----------------
 fs/ntfs3/ntfs_fs.h | 21 ++++++------
 fs/ntfs3/record.c  | 79 ++++++++++++++++++++++++----------------------
 4 files changed, 90 insertions(+), 80 deletions(-)
fs/ntfs3/attrib.c +6 -5
index 940a8293abe9c..526f86a6fe518 100644
@@ -789,7 +789,8 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
 		if (err)
 			goto out;
 
-		attr = mi_find_attr(mi, NULL, type, name, name_len, &le->id);
+		attr = mi_find_attr(ni, mi, NULL, type, name, name_len,
+				    &le->id);
 		if (!attr) {
 			err = -EINVAL;
 			goto bad_inode;
@@ -1197,7 +1198,7 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
 			goto out;
 		}
 
-		attr = mi_find_attr(mi, NULL, ATTR_DATA, NULL, 0, &le->id);
+		attr = mi_find_attr(ni, mi, NULL, ATTR_DATA, NULL, 0, &le->id);
 		if (!attr) {
 			err = -EINVAL;
 			goto out;
@@ -1821,7 +1822,7 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
 				goto out;
 			}
 
-			attr = mi_find_attr(mi, NULL, ATTR_DATA, NULL, 0,
+			attr = mi_find_attr(ni, mi, NULL, ATTR_DATA, NULL, 0,
 					    &le->id);
 			if (!attr) {
 				err = -EINVAL;
@@ -2066,8 +2067,8 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
 				}
 
 				/* Look for required attribute. */
-				attr = mi_find_attr(mi, NULL, ATTR_DATA, NULL,
-						    0, &le->id);
+				attr = mi_find_attr(ni, mi, NULL, ATTR_DATA,
+						    NULL, 0, &le->id);
 				if (!attr) {
 					err = -EINVAL;
 					goto out;
fs/ntfs3/frecord.c +31 -28

226 lines not on this page · raw message

fs/ntfs3/ntfs_fs.h +11 -10
index 919fb3f36af0e..11be9a6f041cf 100644
@@ -746,23 +746,24 @@ int mi_get(struct ntfs_sb_info *sbi, CLST rno, struct mft_inode **mi);
 void mi_put(struct mft_inode *mi);
 int mi_init(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno);
 int mi_read(struct mft_inode *mi, bool is_mft);
-struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr);
-// TODO: id?
-struct ATTRIB *mi_find_attr(struct mft_inode *mi, struct ATTRIB *attr,
-			    enum ATTR_TYPE type, const __le16 *name,
-			    u8 name_len, const __le16 *id);
-static inline struct ATTRIB *rec_find_attr_le(struct mft_inode *rec,
+struct ATTRIB *mi_enum_attr(struct ntfs_inode *ni, struct mft_inode *mi,
+			    struct ATTRIB *attr);
+struct ATTRIB *mi_find_attr(struct ntfs_inode *ni, struct mft_inode *mi,
+			    struct ATTRIB *attr, enum ATTR_TYPE type,
+			    const __le16 *name, u8 name_len, const __le16 *id);
+static inline struct ATTRIB *rec_find_attr_le(struct ntfs_inode *ni,
+					      struct mft_inode *rec,
 					      struct ATTR_LIST_ENTRY *le)
 {
-	return mi_find_attr(rec, NULL, le->type, le_name(le), le->name_len,
+	return mi_find_attr(ni, rec, NULL, le->type, le_name(le), le->name_len,
 			    &le->id);
 }
 int mi_write(struct mft_inode *mi, int wait);
 int mi_format_new(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno,
 		  __le16 flags, bool is_mft);
-struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
-			      const __le16 *name, u8 name_len, u32 asize,
-			      u16 name_off);
+struct ATTRIB *mi_insert_attr(struct ntfs_inode *ni, struct mft_inode *mi,
+			      enum ATTR_TYPE type, const __le16 *name,
+			      u8 name_len, u32 asize, u16 name_off);
 
 bool mi_remove_attr(struct ntfs_inode *ni, struct mft_inode *mi,
 		    struct ATTRIB *attr);
fs/ntfs3/record.c +42 -37

216 lines not on this page · raw message

Signature · 1 line
2.53.0
author maintainer
#548 lore raw

PATCH 528/1376 fs/ntfs3: fix KMSAN uninit-value in ni_create_attr_list

In reply to Greg Kroah-Hartman

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

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

From: Nirbhay Sharma <[email protected]>

[ Upstream commit 5f33da04e6ceee849e76e6592cc283c72fef7af9 ]

The call to kmalloc() to allocate the attribute list buffer is given a size of al_aligned(rs). This size can be larger than the data subsequently copied into the buffer, leaving trailing bytes uninitialized.

This can trigger a KMSAN "uninit-value" warning if that memory is later accessed.

Fix this by using kzalloc() instead, which ensures the entire allocated buffer is zero-initialized, preventing the warning.

Stable-dep-of: 7c4841e2a627 ("fs/ntfs3: fix slab-out-of-bounds write in ni_create_attr_list()")

---
 fs/ntfs3/frecord.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ntfs3/frecord.c +1 -1
index b2791327af22f..162a6c038000e 100644
@@ -826,7 +826,7 @@ int ni_create_attr_list(struct ntfs_inode *ni)
 	 * Skip estimating exact memory requirement.
 	 * Looks like one record_size is always enough.
 	 */
-	le = kmalloc(al_aligned(rs), GFP_NOFS);
+	le = kzalloc(al_aligned(rs), GFP_NOFS);
 	if (!le)
 		return -ENOMEM;
 
Signature · 1 line
2.53.0
author maintainer
#549 lore raw

PATCH 529/1376 fs/ntfs3: fix slab-out-of-bounds write in ni_create_attr_list()

In reply to Greg Kroah-Hartman

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

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

From: HE WEI(ギカク) <[email protected]>

[ Upstream commit 7c4841e2a62794a3bab7c1ff0540580f387e377f ]

ni_create_attr_list() allocates a fixed buffer of al_aligned(record_size) (== record_size) bytes and then walks every attribute of the primary MFT record, writing one ATTR_LIST_ENTRY per attribute and advancing the cursor by le_size(name_len), with no check against the end of the buffer; the total size is only computed after the loop.

A minimum-size resident attribute occupies SIZEOF_RESIDENT (0x18 = 24) bytes on disk, but an unnamed attribute expands to le_size(0) (0x20 = 32) bytes in the list. Because the number of attributes in a record is not bounded (mi_enum_attr() accepts arbitrarily many equal-type, nameless minimum-size attributes), a crafted record packed with such attributes produces a list larger than record_size and overflows the heap buffer.

This is reachable from a crafted, loop-mounted NTFS image: opening the file and adding an attribute (e.g. via setxattr) drives ntfs_set_ea() -> ni_insert_resident() -> ni_insert_attr() -> ni_ins_attr_ext() -> ni_create_attr_list().

  BUG: KASAN: slab-out-of-bounds in ni_create_attr_list+0xc48/0x1058
  Write of size 4 at addr ffff000008984c00 by task setfattr/345
   ni_create_attr_list+0xc48/0x1058
   ni_ins_attr_ext+0x510/0x7c0
   ni_insert_attr+0x3f8/0x70c
   ni_insert_resident+0xc8/0x3b0
   ntfs_set_ea+0x66c/0xd28
   ntfs_setxattr+0x4d8/0x5b0
   __arm64_sys_setxattr+0xa4/0x124
  Allocated by task 345:
   ni_create_attr_list+0x188/0x1058
  The buggy address belongs to the cache kmalloc-1k of size 1024
  (the write lands at object+1024).

Size the buffer from the actual attributes instead of assuming a single record_size is always enough.

Fixes 4342306f0f0d ("fs/ntfs3: Add file operations and implementation")
---
 fs/ntfs3/frecord.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)
fs/ntfs3/frecord.c +16 -4
index 162a6c038000e..45e8d73d38f8f 100644
@@ -823,10 +823,23 @@ int ni_create_attr_list(struct ntfs_inode *ni)
 	rs = sbi->record_size;
 
 	/*
-	 * Skip estimating exact memory requirement.
-	 * Looks like one record_size is always enough.
+	 * Compute the exact size of the attribute list.  Each attribute in the
+	 * record yields one ATTR_LIST_ENTRY of le_size(name_len) bytes.  The
+	 * minimum on-disk attribute is SIZEOF_RESIDENT (0x18) bytes, but an
+	 * unnamed one expands to le_size(0) (0x20) here, so a record crafted
+	 * with many such attributes needs more than a single record_size; the
+	 * previous fixed kzalloc(record_size) could therefore be overflowed by
+	 * an attacker-controlled record.
 	 */
-	le = kzalloc(al_aligned(rs), GFP_NOFS);
+	lsize = 0;
+	attr = NULL;
+	while ((attr = mi_enum_attr(ni, &ni->mi, attr)))
+		lsize += le_size(attr->name_len);
+
+	if (!lsize)
+		return -EINVAL;
+
+	le = kzalloc(al_aligned(lsize), GFP_NOFS);
 	if (!le)
 		return -ENOMEM;
 
@@ -836,7 +849,6 @@ int ni_create_attr_list(struct ntfs_inode *ni)
 	attr = NULL;
 	nb = 0;
 	free_b = 0;
-	attr = NULL;
 
 	for (; (attr = mi_enum_attr(ni, &ni->mi, attr)); le = Add2Ptr(le, sz)) {
 		sz = le_size(attr->name_len);
Signature · 1 line
2.53.0
author maintainer
#550 lore raw

PATCH 530/1376 hfsplus: validate thread record before delete key rebuild

In reply to Greg Kroah-Hartman

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

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

From: Kyle Zeng <[email protected]>

[ Upstream commit e2ea5cac61acfc11dad22f1d2d4bc71d56c52a20 ]

hfsplus_delete_cat() is called with str == NULL when the last open reference to an unlinked HFS+ hardlink backing inode is closed. In that case, the function finds the catalog thread by CNID and rebuilds the catalog key from thread.nodeName.

That reconstruction path reads thread.nodeName.length directly from the catalog B-tree into fd.search_key and then copies length * 2 bytes into fd.search_key->cat.name.unicode. It does not first check that the found record is a thread record or that its size matches the thread name.

A corrupted image can therefore provide an oversized thread name length and make hfs_bnode_read() write past the catalog search-key allocation.

Read the CNID record through hfsplus_brec_read_cat(), which bounds the record read to sizeof(hfsplus_cat_entry) and verifies that a thread record's size exactly matches nodeName.length. Together, these checks ensure an accepted thread name fits HFSPLUS_MAX_STRLEN. Reject non-thread records before building the delete key from the validated thread name.

Share the thread-record-type helper between hfsplus_find_cat() and hfsplus_delete_cat().

---
 fs/hfsplus/catalog.c    | 25 ++++++++++++-------------
 fs/hfsplus/hfsplus_fs.h |  6 ++++++
 2 files changed, 18 insertions(+), 13 deletions(-)
fs/hfsplus/catalog.c +12 -13
index dc3f98ec5e2d2..7a9c72e4e4f2a 100644
@@ -204,7 +204,7 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
 		return err;
 
 	type = be16_to_cpu(tmp.type);
-	if (type != HFSPLUS_FOLDER_THREAD && type != HFSPLUS_FILE_THREAD) {
+	if (!is_hfs_thread_record_type(type)) {
 		pr_err("found bad thread record in catalog\n");
 		return -EIO;
 	}
@@ -350,23 +350,22 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, const struct qstr *str)
 		goto out;
 
 	if (!str) {
-		int len;
+		hfsplus_cat_entry entry = {0};
 
 		hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid);
-		err = hfs_brec_find(&fd, hfs_find_rec_by_key);
+		err = hfsplus_brec_read_cat(&fd, &entry);
 		if (err)
 			goto out;
 
-		off = fd.entryoffset +
-			offsetof(struct hfsplus_cat_thread, nodeName);
-		fd.search_key->cat.parent = cpu_to_be32(dir->i_ino);
-		hfs_bnode_read(fd.bnode,
-			&fd.search_key->cat.name.length, off, 2);
-		len = be16_to_cpu(fd.search_key->cat.name.length) * 2;
-		hfs_bnode_read(fd.bnode,
-			&fd.search_key->cat.name.unicode,
-			off + 2, len);
-		fd.search_key->key_len = cpu_to_be16(6 + len);
+		type = be16_to_cpu(entry.type);
+		if (!is_hfs_thread_record_type(type)) {
+			pr_err("found bad thread record in catalog\n");
+			err = -EIO;
+			goto out;
+		}
+
+		hfsplus_cat_build_key_uni(fd.search_key, dir->i_ino,
+					  &entry.thread.nodeName);
 	} else {
 		err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str);
 		if (unlikely(err))
fs/hfsplus/hfsplus_fs.h +6 -0
index 11cef30803d5a..f4b9c7e2491c9 100644
@@ -543,6 +543,12 @@ static inline u32 hfsplus_cat_thread_size(const struct hfsplus_cat_thread *threa
 	       be16_to_cpu(thread->nodeName.length) * sizeof(hfsplus_unichr);
 }
 
+static inline
+bool is_hfs_thread_record_type(u16 type)
+{
+	return type == HFSPLUS_FOLDER_THREAD || type == HFSPLUS_FILE_THREAD;
+}
+
 int hfsplus_brec_read_cat(struct hfs_find_data *fd, hfsplus_cat_entry *entry);
 
 /*
Signature · 1 line
2.53.0
author maintainer
#551 lore raw

PATCH 531/1376 wifi: ath11k: cap out-of-range rx MCS instead of leaving bogus rate

In reply to Greg Kroah-Hartman

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

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

From: Baochen Qiang <[email protected]>

[ Upstream commit 12b09e478aa7459b7893a695ef77682202f2da83 ]

ath11k can receive HT/VHT/HE frames whose reported MCS is above the maximum that can be expressed in the corresponding mac80211 rate space (e.g. an HE frame reported with MCS 12, while HE tops out at MCS 11).

The frame itself is valid and decodes correctly, but for such a frame ath11k_dp_rx_h_rate() leaves rx_status->rate_idx set to the out-of-range value and never assigns rx_status->encoding, so it stays RX_ENC_LEGACY from the ath11k_dp_rx_h_ppdu() initialization. Once that frame reaches mac80211 it trips the rate sanity check and the frame is dropped with a splat:

ath11k_pci 0000:03:00.0: Received with invalid mcs in HE mode 12

  WARNING: CPU: 0 PID: 0 at net/mac80211/rx.c:5433 ieee80211_rx_list+0xb0a/0xe90 [mac80211]

Dropping the frame would discard otherwise valid data, so instead cap the reported MCS to the maximum the rate space can express and deliver the frame. Set rx_status->encoding before the range check and assign rate_idx from the capped value, so a frame with an out-of-range MCS no longer leaves partial or bogus rate metadata behind. Also downgrade the logging level since they are not treated as invalid frames now. The only loss is that such a frame is reported as the capped MCS in the rx rate statistics.

Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.41

---
 drivers/net/wireless/ath/ath11k/dp_rx.c | 30 ++++++++++++-------------
 1 file changed, 15 insertions(+), 15 deletions(-)
drivers/net/wireless/ath/ath11k/dp_rx.c +15 -15
index 6cc252d00ef13..4935cfdc9adc4 100644
@@ -2332,10 +2332,10 @@ static void ath11k_dp_rx_h_rate(struct ath11k *ar, struct hal_rx_desc *rx_desc,
 	case RX_MSDU_START_PKT_TYPE_11N:
 		rx_status->encoding = RX_ENC_HT;
 		if (rate_mcs > ATH11K_HT_MCS_MAX) {
-			ath11k_warn(ar->ab,
-				    "Received with invalid mcs in HT mode %d\n",
-				     rate_mcs);
-			break;
+			ath11k_dbg(ar->ab, ATH11K_DBG_DP_RX,
+				   "Received HT frame with out-of-range mcs %d, capping to %d\n",
+				   rate_mcs, ATH11K_HT_MCS_MAX);
+			rate_mcs = ATH11K_HT_MCS_MAX;
 		}
 		rx_status->rate_idx = rate_mcs + (8 * (nss - 1));
 		if (sgi)
@@ -2344,13 +2344,13 @@ static void ath11k_dp_rx_h_rate(struct ath11k *ar, struct hal_rx_desc *rx_desc,
 		break;
 	case RX_MSDU_START_PKT_TYPE_11AC:
 		rx_status->encoding = RX_ENC_VHT;
-		rx_status->rate_idx = rate_mcs;
 		if (rate_mcs > ATH11K_VHT_MCS_MAX) {
-			ath11k_warn(ar->ab,
-				    "Received with invalid mcs in VHT mode %d\n",
-				     rate_mcs);
-			break;
+			ath11k_dbg(ar->ab, ATH11K_DBG_DP_RX,
+				   "Received VHT frame with out-of-range mcs %d, capping to %d\n",
+				   rate_mcs, ATH11K_VHT_MCS_MAX);
+			rate_mcs = ATH11K_VHT_MCS_MAX;
 		}
+		rx_status->rate_idx = rate_mcs;
 		rx_status->nss = nss;
 		if (sgi)
 			rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
@@ -2360,14 +2360,14 @@ static void ath11k_dp_rx_h_rate(struct ath11k *ar, struct hal_rx_desc *rx_desc,
 			rx_status->enc_flags |= RX_ENC_FLAG_LDPC;
 		break;
 	case RX_MSDU_START_PKT_TYPE_11AX:
-		rx_status->rate_idx = rate_mcs;
+		rx_status->encoding = RX_ENC_HE;
 		if (rate_mcs > ATH11K_HE_MCS_MAX) {
-			ath11k_warn(ar->ab,
-				    "Received with invalid mcs in HE mode %d\n",
-				    rate_mcs);
-			break;
+			ath11k_dbg(ar->ab, ATH11K_DBG_DP_RX,
+				   "Received HE frame with out-of-range mcs %d, capping to %d\n",
+				   rate_mcs, ATH11K_HE_MCS_MAX);
+			rate_mcs = ATH11K_HE_MCS_MAX;
 		}
-		rx_status->encoding = RX_ENC_HE;
+		rx_status->rate_idx = rate_mcs;
 		rx_status->nss = nss;
 		rx_status->he_gi = ath11k_mac_he_gi_to_nl80211_he_gi(sgi);
 		rx_status->bw = ath11k_mac_bw_to_mac80211_bw(bw);
Signature · 1 line
2.53.0
author maintainer
#552 lore raw

PATCH 532/1376 x86/entry/fred: Encode frame pointer on entry

In reply to Greg Kroah-Hartman

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

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

From: David Stevens <[email protected]>

[ Upstream commit dab01c597f6bd40e0efe7da967b8374ca1971b79 ]

Add missing ENCODE_FRAME_POINTER macro invocation into FRED_ENTER macro, to prevent the unwinder from encountering a NULL stack frame pointer when CONFIG_UNWINDER_FRAME_POINTER is enabled

---
 arch/x86/entry/entry_64_fred.S | 2 ++
 1 file changed, 2 insertions(+)
arch/x86/entry/entry_64_fred.S +2 -0
index 0ca9db540b16d..3c1bf47af56c2 100644
@@ -6,6 +6,7 @@
 #include <linux/export.h>
 
 #include <asm/asm.h>
+#include <asm/frame.h>
 #include <asm/fred.h>
 #include <asm/segment.h>
 
@@ -18,6 +19,7 @@
 	UNWIND_HINT_END_OF_STACK
 	ANNOTATE_NOENDBR
 	PUSH_AND_CLEAR_REGS
+	ENCODE_FRAME_POINTER
 	movq	%rsp, %rdi	/* %rdi -> pt_regs */
 .endm
 
Signature · 1 line
2.53.0
author maintainer
#553 lore raw

PATCH 533/1376 firmware: arm_scmi: Publish channel state before callbacks

In reply to Greg Kroah-Hartman

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

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

From: Sudeep Holla <[email protected]>

[ Upstream commit 0314900dcdde044af0208fed212035dbfaa55843 ]

Transport setup can enable callbacks before the setup routine returns. mailbox_chan_setup() registers the mailbox client with mbox_request_channel(), and the mailbox controller startup path can enable interrupt delivery before SCMI mailbox channel state has been published. Similarly, smc_chan_setup() requests the optional A2P completion IRQ before the SMC transport has made its cinfo pointer visible.

If a pending or spurious callback fires in those windows, the transport RX callback can dereference a NULL transport cinfo pointer. Publishing only the transport-private pointer is not sufficient either: an early callback can enter the SCMI core before scmi_chan_setup() has assigned cinfo->handle.
The core derives scmi_info from cinfo->handle in the RX path, so a NULL handle can still fault even when the transport-private cinfo is valid.

Assign cinfo->handle before invoking the transport setup callback. Publish the mailbox and SMC transport-private channel state before requesting the mailbox channels or IRQ, and clear the early-published pointers again on setup failure. Also unwind mailbox setup devres resources on failure so an optional RX setup error that is ignored by the core does not leave stale transport state behind.

Fixes 5c8a47a5a91d ("firmware: arm_scmi: Make scmi core independent of the transport type")
---
 drivers/firmware/arm_scmi/driver.c             |  2 +-
 drivers/firmware/arm_scmi/transports/mailbox.c | 18 +++++++++++++-----
 drivers/firmware/arm_scmi/transports/smc.c     | 15 +++++++++------
 3 files changed, 23 insertions(+), 12 deletions(-)
drivers/firmware/arm_scmi/driver.c +1 -1
index 79866f3b6b3e7..1901cc1ec8dd0 100644
@@ -2657,6 +2657,7 @@ static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_node,
 
 	cinfo->id = prot_id;
 	cinfo->dev = &tdev->dev;
+	cinfo->handle = &info->handle;
 	ret = info->desc->ops->chan_setup(cinfo, info->dev, tx);
 	if (ret) {
 		of_node_put(of_node);
@@ -2689,7 +2690,6 @@ static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_node,
 		return ret;
 	}
 
-	cinfo->handle = &info->handle;
 	return 0;
 }
 
drivers/firmware/arm_scmi/transports/mailbox.c +13 -5
index e3d5f75609905..f4847569b42c8 100644
@@ -208,13 +208,18 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
 	cl->tx_block = false;
 	cl->knows_txdone = tx;
 
+	cinfo->transport_info = smbox;
+	smbox->cinfo = cinfo;
+	mutex_init(&smbox->chan_lock);
+
 	smbox->chan = mbox_request_channel(cl, tx ? 0 : p2a_chan);
 	if (IS_ERR(smbox->chan)) {
 		ret = PTR_ERR(smbox->chan);
+		smbox->chan = NULL;
 		if (ret != -EPROBE_DEFER)
 			dev_err(cdev,
 				"failed to request SCMI %s mailbox\n", desc);
-		return ret;
+		goto err_clear_cinfo;
 	}
 
 	/* Additional unidirectional channel for TX if needed */
@@ -238,11 +243,14 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
 		}
 	}
 
-	cinfo->transport_info = smbox;
-	smbox->cinfo = cinfo;
-	mutex_init(&smbox->chan_lock);
-
 	return 0;
+
+err_clear_cinfo:
+	cinfo->transport_info = NULL;
+	smbox->cinfo = NULL;
+	devm_iounmap(dev, smbox->shmem);
+	devm_kfree(dev, smbox);
+	return ret;
 }
 
 static int mailbox_chan_free(int id, void *p, void *data)
drivers/firmware/arm_scmi/transports/smc.c +9 -6
index f8dd108777f9b..2a35434a2b7f5 100644
@@ -169,6 +169,13 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
 		scmi_info->param_page = SHMEM_PAGE(res.start);
 		scmi_info->param_offset = SHMEM_OFFSET(res.start);
 	}
+
+	scmi_info->func_id = func_id;
+	scmi_info->cap_id = cap_id;
+	scmi_info->cinfo = cinfo;
+	smc_channel_lock_init(scmi_info);
+	cinfo->transport_info = scmi_info;
+
 	/*
 	 * If there is an interrupt named "a2p", then the service and
 	 * completion of a message is signaled by an interrupt rather than by
@@ -180,18 +187,14 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
 				  IRQF_NO_SUSPEND, dev_name(dev), scmi_info);
 		if (ret) {
 			dev_err(dev, "failed to setup SCMI smc irq\n");
+			cinfo->transport_info = NULL;
+			scmi_info->cinfo = NULL;
 			return ret;
 		}
 	} else {
 		cinfo->no_completion_irq = true;
 	}
 
-	scmi_info->func_id = func_id;
-	scmi_info->cap_id = cap_id;
-	scmi_info->cinfo = cinfo;
-	smc_channel_lock_init(scmi_info);
-	cinfo->transport_info = scmi_info;
-
 	return 0;
 }
 
Signature · 1 line
2.53.0
author maintainer
#554 lore raw

PATCH 534/1376 firmware: arm_scmi: Unregister device notifier before IDR teardown

In reply to Greg Kroah-Hartman

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

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

From: Sudeep Holla <[email protected]>

[ Upstream commit 66a0bbf30cc14140fe13f63cd594a7c1ee352b75 ]

The requested-devices notifier looks up protocol fwnodes from the active_protocols IDR. During remove, unregister the notifier before releasing and destroying active_protocols so no notifier callback can race with the IDR teardown.

Keep the bus notifier registered until after the protocol state is torn down, matching the existing remove ordering for SCMI bus users.

Fixes 53b8c25df708 ("firmware: arm_scmi: Add common notifier helpers")
---
 drivers/firmware/arm_scmi/driver.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/firmware/arm_scmi/driver.c +3 -2
index 1901cc1ec8dd0..bb503028c1f5e 100644
@@ -3250,6 +3250,9 @@ static void scmi_remove(struct platform_device *pdev)
 	list_del(&info->node);
 	mutex_unlock(&scmi_list_mutex);
 
+	blocking_notifier_chain_unregister(&scmi_requested_devices_nh,
+					   &info->dev_req_nb);
+
 	scmi_notification_exit(&info->handle);
 
 	mutex_lock(&info->protocols_mtx);
@@ -3260,8 +3263,6 @@ static void scmi_remove(struct platform_device *pdev)
 		of_node_put(child);
 	idr_destroy(&info->active_protocols);
 
-	blocking_notifier_chain_unregister(&scmi_requested_devices_nh,
-					   &info->dev_req_nb);
 	bus_unregister_notifier(&scmi_bus_type, &info->bus_nb);
 
 	/* Safe to free channels since no more users */
Signature · 1 line
2.53.0
author maintainer
#555 lore raw

PATCH 535/1376 firmware: arm_scmi: Quiesce notifications before teardown

In reply to Greg Kroah-Hartman

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

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

From: Sudeep Holla <[email protected]>

[ Upstream commit 8e49055d0d495c9c07575ad8e111d9eaf0efb13f ]

scmi_notification_exit() clears and releases the notification instance, but transport callbacks can still deliver incoming notifications until the TX/RX channels are freed. During remove, an RX interrupt in that window can enter scmi_notify() while notification state is being torn down and then dereference freed memory. The same ordering exists on the probe error path after notification initialization.

The notification late-init worker has a separate lifetime issue: protocol event registration queues ni->init_work on the system workqueue, so destroying ni->notify_wq does not drain that work. If the devres group is released while init_work is still pending or running, the late-init worker can dereference the freed notification instance.

Quiesce the notification core before TX/RX channels are torn down, then clean up the channels before releasing the notification core resources. Use disable_work_sync() so future late-init queueing is rejected and any already queued or running late-init work has completed before channel teardown starts.

Fixes 1e7cbfaa66d3 ("firmware: arm_scmi: Free mailbox channels if probe fails")
---
 drivers/firmware/arm_scmi/driver.c | 13 +++++++------
 drivers/firmware/arm_scmi/notify.c | 21 +++++++++++++++++++++
 drivers/firmware/arm_scmi/notify.h |  1 +
 3 files changed, 29 insertions(+), 6 deletions(-)
drivers/firmware/arm_scmi/driver.c +7 -6
index bb503028c1f5e..f69b8e2697415 100644
@@ -3176,7 +3176,7 @@ static int scmi_probe(struct platform_device *pdev)
 			dev_err(dev, "%s", err_str);
 			return 0;
 		}
-		goto notification_exit;
+		goto raw_mode_cleanup;
 	}
 
 	mutex_lock(&scmi_list_mutex);
@@ -3216,17 +3216,18 @@ static int scmi_probe(struct platform_device *pdev)
 
 	return 0;
 
-notification_exit:
+raw_mode_cleanup:
 	if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT))
 		scmi_raw_mode_cleanup(info->raw);
-	scmi_notification_exit(&info->handle);
 clear_dev_req_notifier:
 	blocking_notifier_chain_unregister(&scmi_requested_devices_nh,
 					   &info->dev_req_nb);
 clear_bus_notifier:
 	bus_unregister_notifier(&scmi_bus_type, &info->bus_nb);
 clear_txrx_setup:
+	scmi_notification_quiesce(&info->handle);
 	scmi_cleanup_txrx_channels(info);
+	scmi_notification_exit(&info->handle);
 clear_ida:
 	ida_free(&scmi_id, info->id);
 
@@ -3253,6 +3254,9 @@ static void scmi_remove(struct platform_device *pdev)
 	blocking_notifier_chain_unregister(&scmi_requested_devices_nh,
 					   &info->dev_req_nb);
 
+	/* Stop transport callbacks before tearing down notifications. */
+	scmi_notification_quiesce(&info->handle);
+	scmi_cleanup_txrx_channels(info);
 	scmi_notification_exit(&info->handle);
 
 	mutex_lock(&info->protocols_mtx);
@@ -3265,9 +3269,6 @@ static void scmi_remove(struct platform_device *pdev)
 
 	bus_unregister_notifier(&scmi_bus_type, &info->bus_nb);
 
-	/* Safe to free channels since no more users */
-	scmi_cleanup_txrx_channels(info);
-
 	ida_free(&scmi_id, info->id);
 }
 
drivers/firmware/arm_scmi/notify.c +21 -0
index f042fb8a05026..c4d4337ac3a34 100644
@@ -1685,6 +1685,25 @@ int scmi_notification_init(struct scmi_handle *handle)
 	return -ENOMEM;
 }
 
+/**
+ * scmi_notification_quiesce()  - Stop notification late initialization
+ * @handle: The handle identifying the platform instance to quiesce
+ *
+ * Prevent new late-init work from being queued and wait for any already queued
+ * or running late-init work to complete before transport channels are torn
+ * down.
+ */
+void scmi_notification_quiesce(struct scmi_handle *handle)
+{
+	struct scmi_notify_instance *ni;
+
+	ni = scmi_notification_instance_data_get(handle);
+	if (!ni)
+		return;
+
+	disable_work_sync(&ni->init_work);
+}
+
 /**
  * scmi_notification_exit()  - Shutdown and clean Notification core
  * @handle: The handle identifying the platform instance to shutdown
@@ -1696,6 +1715,8 @@ void scmi_notification_exit(struct scmi_handle *handle)
 	ni = scmi_notification_instance_data_get(handle);
 	if (!ni)
 		return;
+
+	scmi_notification_quiesce(handle);
 	scmi_notification_instance_data_set(handle, NULL);
 
 	/* Destroy while letting pending work complete */
drivers/firmware/arm_scmi/notify.h +1 -0
index 76758a736cf47..f18f98c5ab3ba 100644
@@ -82,6 +82,7 @@ struct scmi_protocol_events {
 };
 
 int scmi_notification_init(struct scmi_handle *handle);
+void scmi_notification_quiesce(struct scmi_handle *handle);
 void scmi_notification_exit(struct scmi_handle *handle);
 int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
 				  const struct scmi_protocol_handle *ph,
Signature · 1 line
2.53.0