The patch below does not apply to the 5.4-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable(a)vger.kernel.org>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From b89ddf4cca43f1269093942cf5c4e457fd45c335 Mon Sep 17 00:00:00 2001
From: Russell King <russell.king(a)oracle.com>
Date: Fri, 5 Nov 2021 16:50:45 +0000
Subject: [PATCH] arm64/bpf: Remove 128MB limit for BPF JIT programs
Commit 91fc957c9b1d ("arm64/bpf: don't allocate BPF JIT programs in module
memory") restricts BPF JIT program allocation to a 128MB region to ensure
BPF programs are still in branching range of each other. However this
restriction should not apply to the aarch64 JIT, since BPF_JMP | BPF_CALL
are implemented as a 64-bit move into a register and then a BLR instruction -
which has the effect of being able to call anything without proximity
limitation.
The practical reason to relax this restriction on JIT memory is that 128MB of
JIT memory can be quickly exhausted, especially where PAGE_SIZE is 64KB - one
page is needed per program. In cases where seccomp filters are applied to
multiple VMs on VM launch - such filters are classic BPF but converted to
BPF - this can severely limit the number of VMs that can be launched. In a
world where we support BPF JIT always on, turning off the JIT isn't always an
option either.
Fixes: 91fc957c9b1d ("arm64/bpf: don't allocate BPF JIT programs in module memory")
Suggested-by: Ard Biesheuvel <ard.biesheuvel(a)linaro.org>
Signed-off-by: Russell King <russell.king(a)oracle.com>
Signed-off-by: Daniel Borkmann <daniel(a)iogearbox.net>
Tested-by: Alan Maguire <alan.maguire(a)oracle.com>
Link: https://lore.kernel.org/bpf/1636131046-5982-2-git-send-email-alan.maguire@o…
diff --git a/arch/arm64/include/asm/extable.h b/arch/arm64/include/asm/extable.h
index 8b300dd28def..72b0e71cc3de 100644
--- a/arch/arm64/include/asm/extable.h
+++ b/arch/arm64/include/asm/extable.h
@@ -33,15 +33,6 @@ do { \
(b)->data = (tmp).data; \
} while (0)
-static inline bool in_bpf_jit(struct pt_regs *regs)
-{
- if (!IS_ENABLED(CONFIG_BPF_JIT))
- return false;
-
- return regs->pc >= BPF_JIT_REGION_START &&
- regs->pc < BPF_JIT_REGION_END;
-}
-
#ifdef CONFIG_BPF_JIT
bool ex_handler_bpf(const struct exception_table_entry *ex,
struct pt_regs *regs);
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index 1b9a1e242612..0af70d9abede 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -44,11 +44,8 @@
#define _PAGE_OFFSET(va) (-(UL(1) << (va)))
#define PAGE_OFFSET (_PAGE_OFFSET(VA_BITS))
#define KIMAGE_VADDR (MODULES_END)
-#define BPF_JIT_REGION_START (_PAGE_END(VA_BITS_MIN))
-#define BPF_JIT_REGION_SIZE (SZ_128M)
-#define BPF_JIT_REGION_END (BPF_JIT_REGION_START + BPF_JIT_REGION_SIZE)
#define MODULES_END (MODULES_VADDR + MODULES_VSIZE)
-#define MODULES_VADDR (BPF_JIT_REGION_END)
+#define MODULES_VADDR (_PAGE_END(VA_BITS_MIN))
#define MODULES_VSIZE (SZ_128M)
#define VMEMMAP_START (-(UL(1) << (VA_BITS - VMEMMAP_SHIFT)))
#define VMEMMAP_END (VMEMMAP_START + VMEMMAP_SIZE)
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 7b21213a570f..e8986e6067a9 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -994,7 +994,7 @@ static struct break_hook bug_break_hook = {
static int reserved_fault_handler(struct pt_regs *regs, unsigned int esr)
{
pr_err("%s generated an invalid instruction at %pS!\n",
- in_bpf_jit(regs) ? "BPF JIT" : "Kernel text patching",
+ "Kernel text patching",
(void *)instruction_pointer(regs));
/* We cannot handle this */
diff --git a/arch/arm64/mm/ptdump.c b/arch/arm64/mm/ptdump.c
index 1c403536c9bb..9bc4066c5bf3 100644
--- a/arch/arm64/mm/ptdump.c
+++ b/arch/arm64/mm/ptdump.c
@@ -41,8 +41,6 @@ static struct addr_marker address_markers[] = {
{ 0 /* KASAN_SHADOW_START */, "Kasan shadow start" },
{ KASAN_SHADOW_END, "Kasan shadow end" },
#endif
- { BPF_JIT_REGION_START, "BPF start" },
- { BPF_JIT_REGION_END, "BPF end" },
{ MODULES_VADDR, "Modules start" },
{ MODULES_END, "Modules end" },
{ VMALLOC_START, "vmalloc() area" },
diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
index 3a8a7140a9bf..86c9dc0681cc 100644
--- a/arch/arm64/net/bpf_jit_comp.c
+++ b/arch/arm64/net/bpf_jit_comp.c
@@ -1141,15 +1141,12 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
u64 bpf_jit_alloc_exec_limit(void)
{
- return BPF_JIT_REGION_SIZE;
+ return VMALLOC_END - VMALLOC_START;
}
void *bpf_jit_alloc_exec(unsigned long size)
{
- return __vmalloc_node_range(size, PAGE_SIZE, BPF_JIT_REGION_START,
- BPF_JIT_REGION_END, GFP_KERNEL,
- PAGE_KERNEL, 0, NUMA_NO_NODE,
- __builtin_return_address(0));
+ return vmalloc(size);
}
void bpf_jit_free_exec(void *addr)
The rseq rseq_cs.ptr.{ptr32,padding} uapi endianness handling is
entirely wrong on 32-bit little endian: a preprocessor logic mistake
wrongly uses the big endian field layout on 32-bit little endian
architectures.
Fortunately, those ptr32 accessors were never used within the kernel,
and only meant as a convenience for user-space.
While working on fixing the ppc32 support in librseq [1], I made sure
all 32-bit little endian architectures stopped depending on little
endian byte ordering by using the ptr32 field. It led me to discover
this wrong ptr32 field ordering on little endian.
Because it is already exposed as a UAPI, all we can do for the existing
fields is document the wrong behavior and encourage users to use
alternative mechanisms.
Introduce a new rseq_cs.arch field with correct field ordering. Use this
opportunity to improve the layout so accesses to architecture fields on
both 32-bit and 64-bit architectures are done through the same field
hierarchy, which is much nicer than the previous scheme.
The intended use is now:
* rseq_thread_area->rseq_cs.ptr64: Access the 64-bit value of the rseq_cs
pointer. Available on all
architectures (unchanged).
* rseq_thread_area->rseq_cs.arch.ptr: Access the architecture specific
layout of the rseq_cs pointer. This
is a 32-bit field on 32-bit
architectures, and a 64-bit field on
64-bit architectures.
Link: https://git.kernel.org/pub/scm/libs/librseq/librseq.git/ [1]
Fixes: ec9c82e03a74 ("rseq: uapi: Declare rseq_cs field as union, update includes")
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers(a)efficios.com>
Cc: Florian Weimer <fw(a)deneb.enyo.de>
Cc: Thomas Gleixner <tglx(a)linutronix.de>
Cc: linux-api(a)vger.kernel.org
Cc: Peter Zijlstra <peterz(a)infradead.org>
Cc: Boqun Feng <boqun.feng(a)gmail.com>
Cc: Andy Lutomirski <luto(a)amacapital.net>
Cc: Dave Watson <davejwatson(a)fb.com>
Cc: Paul Turner <pjt(a)google.com>
Cc: Andrew Morton <akpm(a)linux-foundation.org>
Cc: Russell King <linux(a)arm.linux.org.uk>
Cc: "H . Peter Anvin" <hpa(a)zytor.com>
Cc: Andi Kleen <andi(a)firstfloor.org>
Cc: Christian Brauner <christian.brauner(a)ubuntu.com>
Cc: Ben Maurer <bmaurer(a)fb.com>
Cc: Steven Rostedt <rostedt(a)goodmis.org>
Cc: Josh Triplett <josh(a)joshtriplett.org>
Cc: Linus Torvalds <torvalds(a)linux-foundation.org>
Cc: Catalin Marinas <catalin.marinas(a)arm.com>
Cc: Will Deacon <will.deacon(a)arm.com>
Cc: Michael Kerrisk <mtk.manpages(a)gmail.com>
Cc: Joel Fernandes <joelaf(a)google.com>
Cc: Paul E. McKenney <paulmck(a)kernel.org>
---
include/uapi/linux/rseq.h | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/include/uapi/linux/rseq.h b/include/uapi/linux/rseq.h
index 9a402fdb60e9..68f61cdb45db 100644
--- a/include/uapi/linux/rseq.h
+++ b/include/uapi/linux/rseq.h
@@ -108,6 +108,12 @@ struct rseq {
*/
union {
__u64 ptr64;
+
+ /*
+ * The "ptr" field layout is broken on little-endian
+ * 32-bit architectures due to wrong preprocessor logic.
+ * DO NOT USE.
+ */
#ifdef __LP64__
__u64 ptr;
#else
@@ -121,6 +127,23 @@ struct rseq {
#endif /* ENDIAN */
} ptr;
#endif
+
+ /*
+ * The "arch" field provides architecture accessor for
+ * the ptr field based on architecture pointer size and
+ * endianness.
+ */
+ struct {
+#ifdef __LP64__
+ __u64 ptr;
+#elif defined(__BYTE_ORDER) ? (__BYTE_ORDER == __BIG_ENDIAN) : defined(__BIG_ENDIAN)
+ __u32 padding; /* Initialized to zero. */
+ __u32 ptr;
+#else
+ __u32 ptr;
+ __u32 padding; /* Initialized to zero. */
+#endif
+ } arch;
} rseq_cs;
/*
--
2.17.1
The patch below does not apply to the 5.16-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable(a)vger.kernel.org>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 244a36e50da05c33b860d20638ee4628017a5334 Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime(a)cerno.tech>
Date: Wed, 17 Nov 2021 10:45:22 +0100
Subject: [PATCH] drm/vc4: kms: Wait for the commit before increasing our clock
rate
Several DRM/KMS atomic commits can run in parallel if they affect
different CRTC. These commits share the global HVS state, so we have
some code to make sure we run commits in sequence. This synchronization
code is one of the first thing that runs in vc4_atomic_commit_tail().
Another constraints we have is that we need to make sure the HVS clock
gets a boost during the commit. That code relies on clk_set_min_rate and
will remove the old minimum and set a new one. We also need another,
temporary, minimum for the duration of the commit.
The algorithm is thus to set a temporary minimum, drop the previous
one, do the commit, and finally set the minimum for the current mode.
However, the part that sets the temporary minimum and drops the older
one runs before the commit synchronization code.
Thus, under the proper conditions, we can end up mixing up the minimums
and ending up with the wrong one for our current step.
To avoid it, let's move the clock setup in the protected section.
Fixes: d7d96c00e585 ("drm/vc4: hvs: Boost the core clock during modeset")
Signed-off-by: Maxime Ripard <maxime(a)cerno.tech>
Reviewed-by: Dave Stevenson <dave.stevenson(a)raspberrypi.com>
Tested-by: Jian-Hong Pan <jhp(a)endlessos.org>
[danvet: re-apply this from 0c980a006d3f ("drm/vc4: kms: Wait for the
commit before increasing our clock rate") because I lost that part in
my merge resolution in 99b03ca651f1 ("Merge v5.16-rc5 into drm-next")]
Fixes: 99b03ca651f1 ("Merge v5.16-rc5 into drm-next")
Acked-by: Maxime Ripard <maxime(a)cerno.tech>
Signed-off-by: Daniel Vetter <daniel.vetter(a)intel.com>
Link: https://lore.kernel.org/r/20211117094527.146275-2-maxime@cerno.tech
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index bf3706f97ec7..24de29bc1cda 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -365,14 +365,6 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel);
}
- if (vc4->hvs->hvs5) {
- unsigned long core_rate = max_t(unsigned long,
- 500000000,
- new_hvs_state->core_clock_rate);
-
- clk_set_min_rate(hvs->core_clk, core_rate);
- }
-
for (channel = 0; channel < HVS_NUM_CHANNELS; channel++) {
struct drm_crtc_commit *commit;
int ret;
@@ -392,6 +384,13 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
old_hvs_state->fifo_state[channel].pending_commit = NULL;
}
+ if (vc4->hvs->hvs5) {
+ unsigned long core_rate = max_t(unsigned long,
+ 500000000,
+ new_hvs_state->core_clock_rate);
+
+ clk_set_min_rate(hvs->core_clk, core_rate);
+ }
drm_atomic_helper_commit_modeset_disables(dev, state);
vc4_ctm_commit(vc4, state);
The patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable(a)vger.kernel.org>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 244a36e50da05c33b860d20638ee4628017a5334 Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime(a)cerno.tech>
Date: Wed, 17 Nov 2021 10:45:22 +0100
Subject: [PATCH] drm/vc4: kms: Wait for the commit before increasing our clock
rate
Several DRM/KMS atomic commits can run in parallel if they affect
different CRTC. These commits share the global HVS state, so we have
some code to make sure we run commits in sequence. This synchronization
code is one of the first thing that runs in vc4_atomic_commit_tail().
Another constraints we have is that we need to make sure the HVS clock
gets a boost during the commit. That code relies on clk_set_min_rate and
will remove the old minimum and set a new one. We also need another,
temporary, minimum for the duration of the commit.
The algorithm is thus to set a temporary minimum, drop the previous
one, do the commit, and finally set the minimum for the current mode.
However, the part that sets the temporary minimum and drops the older
one runs before the commit synchronization code.
Thus, under the proper conditions, we can end up mixing up the minimums
and ending up with the wrong one for our current step.
To avoid it, let's move the clock setup in the protected section.
Fixes: d7d96c00e585 ("drm/vc4: hvs: Boost the core clock during modeset")
Signed-off-by: Maxime Ripard <maxime(a)cerno.tech>
Reviewed-by: Dave Stevenson <dave.stevenson(a)raspberrypi.com>
Tested-by: Jian-Hong Pan <jhp(a)endlessos.org>
[danvet: re-apply this from 0c980a006d3f ("drm/vc4: kms: Wait for the
commit before increasing our clock rate") because I lost that part in
my merge resolution in 99b03ca651f1 ("Merge v5.16-rc5 into drm-next")]
Fixes: 99b03ca651f1 ("Merge v5.16-rc5 into drm-next")
Acked-by: Maxime Ripard <maxime(a)cerno.tech>
Signed-off-by: Daniel Vetter <daniel.vetter(a)intel.com>
Link: https://lore.kernel.org/r/20211117094527.146275-2-maxime@cerno.tech
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index bf3706f97ec7..24de29bc1cda 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -365,14 +365,6 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel);
}
- if (vc4->hvs->hvs5) {
- unsigned long core_rate = max_t(unsigned long,
- 500000000,
- new_hvs_state->core_clock_rate);
-
- clk_set_min_rate(hvs->core_clk, core_rate);
- }
-
for (channel = 0; channel < HVS_NUM_CHANNELS; channel++) {
struct drm_crtc_commit *commit;
int ret;
@@ -392,6 +384,13 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
old_hvs_state->fifo_state[channel].pending_commit = NULL;
}
+ if (vc4->hvs->hvs5) {
+ unsigned long core_rate = max_t(unsigned long,
+ 500000000,
+ new_hvs_state->core_clock_rate);
+
+ clk_set_min_rate(hvs->core_clk, core_rate);
+ }
drm_atomic_helper_commit_modeset_disables(dev, state);
vc4_ctm_commit(vc4, state);
The patch below does not apply to the 5.16-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable(a)vger.kernel.org>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From e32e5723256a99c5324824503572f743377dd0fe Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime(a)cerno.tech>
Date: Mon, 25 Oct 2021 17:28:55 +0200
Subject: [PATCH] drm/vc4: hdmi: Fix HPD GPIO detection
Prior to commit 6800234ceee0 ("drm/vc4: hdmi: Convert to gpiod"), in the
detect hook, if we had an HPD GPIO we would only rely on it and return
whatever state it was in.
However, that commit changed that by mistake to only consider the case
where we have a GPIO and it returns a logical high, and would fall back
to the other methods otherwise.
Since we can read the EDIDs when the HPD signal is low on some displays,
we changed the detection status from disconnected to connected, and we
would ignore an HPD pulse.
Fixes: 6800234ceee0 ("drm/vc4: hdmi: Convert to gpiod")
Signed-off-by: Maxime Ripard <maxime(a)cerno.tech>
Reviewed-by: Dave Stevenson <dave.stevenson(a)raspberrypi.com>
Link: https://lore.kernel.org/r/20211025152903.1088803-3-maxime@cerno.tech
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 6469645a7ad5..07a67bf6d3a8 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -170,9 +170,9 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev));
- if (vc4_hdmi->hpd_gpio &&
- gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) {
- connected = true;
+ if (vc4_hdmi->hpd_gpio) {
+ if (gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio))
+ connected = true;
} else if (HDMI_READ(HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) {
connected = true;
}
The patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable(a)vger.kernel.org>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From e32e5723256a99c5324824503572f743377dd0fe Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime(a)cerno.tech>
Date: Mon, 25 Oct 2021 17:28:55 +0200
Subject: [PATCH] drm/vc4: hdmi: Fix HPD GPIO detection
Prior to commit 6800234ceee0 ("drm/vc4: hdmi: Convert to gpiod"), in the
detect hook, if we had an HPD GPIO we would only rely on it and return
whatever state it was in.
However, that commit changed that by mistake to only consider the case
where we have a GPIO and it returns a logical high, and would fall back
to the other methods otherwise.
Since we can read the EDIDs when the HPD signal is low on some displays,
we changed the detection status from disconnected to connected, and we
would ignore an HPD pulse.
Fixes: 6800234ceee0 ("drm/vc4: hdmi: Convert to gpiod")
Signed-off-by: Maxime Ripard <maxime(a)cerno.tech>
Reviewed-by: Dave Stevenson <dave.stevenson(a)raspberrypi.com>
Link: https://lore.kernel.org/r/20211025152903.1088803-3-maxime@cerno.tech
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 6469645a7ad5..07a67bf6d3a8 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -170,9 +170,9 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev));
- if (vc4_hdmi->hpd_gpio &&
- gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) {
- connected = true;
+ if (vc4_hdmi->hpd_gpio) {
+ if (gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio))
+ connected = true;
} else if (HDMI_READ(HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) {
connected = true;
}
The patch below does not apply to the 5.16-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable(a)vger.kernel.org>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From a64ff88cb5eb0b9a6855a24ff326e948931e3a8e Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime(a)cerno.tech>
Date: Mon, 25 Oct 2021 16:11:11 +0200
Subject: [PATCH] drm/vc4: hdmi: Check the device state in prepare()
Even though we already check that the encoder->crtc pointer is there
during in startup(), which is part of the open() path in ASoC, nothing
guarantees that our encoder state won't change between the time when we
open the device and the time we prepare it.
Move the sanity checks we do in startup() to a helper and call it from
prepare().
Link: https://lore.kernel.org/r/20211025141113.702757-8-maxime@cerno.tech
Fixes: 91e99e113929 ("drm/vc4: hdmi: Register HDMI codec")
Acked-by: Daniel Vetter <daniel.vetter(a)ffwll.ch>
Signed-off-by: Maxime Ripard <maxime(a)cerno.tech>
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 71e3d1044d84..0adaa6f7eaef 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -1395,20 +1395,36 @@ static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai)
return snd_soc_card_get_drvdata(card);
}
+static bool vc4_hdmi_audio_can_stream(struct vc4_hdmi *vc4_hdmi)
+{
+ struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
+
+ lockdep_assert_held(&vc4_hdmi->mutex);
+
+ /*
+ * The encoder doesn't have a CRTC until the first modeset.
+ */
+ if (!encoder->crtc)
+ return false;
+
+ /*
+ * If the encoder is currently in DVI mode, treat the codec DAI
+ * as missing.
+ */
+ if (!(HDMI_READ(HDMI_RAM_PACKET_CONFIG) & VC4_HDMI_RAM_PACKET_ENABLE))
+ return false;
+
+ return true;
+}
+
static int vc4_hdmi_audio_startup(struct device *dev, void *data)
{
struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
- struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
unsigned long flags;
mutex_lock(&vc4_hdmi->mutex);
- /*
- * If the HDMI encoder hasn't probed, or the encoder is
- * currently in DVI mode, treat the codec dai as missing.
- */
- if (!encoder->crtc || !(HDMI_READ(HDMI_RAM_PACKET_CONFIG) &
- VC4_HDMI_RAM_PACKET_ENABLE)) {
+ if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) {
mutex_unlock(&vc4_hdmi->mutex);
return -ENODEV;
}
@@ -1538,6 +1554,11 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
mutex_lock(&vc4_hdmi->mutex);
+ if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) {
+ mutex_unlock(&vc4_hdmi->mutex);
+ return -EINVAL;
+ }
+
vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate);
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
The patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable(a)vger.kernel.org>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From a64ff88cb5eb0b9a6855a24ff326e948931e3a8e Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime(a)cerno.tech>
Date: Mon, 25 Oct 2021 16:11:11 +0200
Subject: [PATCH] drm/vc4: hdmi: Check the device state in prepare()
Even though we already check that the encoder->crtc pointer is there
during in startup(), which is part of the open() path in ASoC, nothing
guarantees that our encoder state won't change between the time when we
open the device and the time we prepare it.
Move the sanity checks we do in startup() to a helper and call it from
prepare().
Link: https://lore.kernel.org/r/20211025141113.702757-8-maxime@cerno.tech
Fixes: 91e99e113929 ("drm/vc4: hdmi: Register HDMI codec")
Acked-by: Daniel Vetter <daniel.vetter(a)ffwll.ch>
Signed-off-by: Maxime Ripard <maxime(a)cerno.tech>
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 71e3d1044d84..0adaa6f7eaef 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -1395,20 +1395,36 @@ static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai)
return snd_soc_card_get_drvdata(card);
}
+static bool vc4_hdmi_audio_can_stream(struct vc4_hdmi *vc4_hdmi)
+{
+ struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
+
+ lockdep_assert_held(&vc4_hdmi->mutex);
+
+ /*
+ * The encoder doesn't have a CRTC until the first modeset.
+ */
+ if (!encoder->crtc)
+ return false;
+
+ /*
+ * If the encoder is currently in DVI mode, treat the codec DAI
+ * as missing.
+ */
+ if (!(HDMI_READ(HDMI_RAM_PACKET_CONFIG) & VC4_HDMI_RAM_PACKET_ENABLE))
+ return false;
+
+ return true;
+}
+
static int vc4_hdmi_audio_startup(struct device *dev, void *data)
{
struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
- struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
unsigned long flags;
mutex_lock(&vc4_hdmi->mutex);
- /*
- * If the HDMI encoder hasn't probed, or the encoder is
- * currently in DVI mode, treat the codec dai as missing.
- */
- if (!encoder->crtc || !(HDMI_READ(HDMI_RAM_PACKET_CONFIG) &
- VC4_HDMI_RAM_PACKET_ENABLE)) {
+ if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) {
mutex_unlock(&vc4_hdmi->mutex);
return -ENODEV;
}
@@ -1538,6 +1554,11 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
mutex_lock(&vc4_hdmi->mutex);
+ if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) {
+ mutex_unlock(&vc4_hdmi->mutex);
+ return -EINVAL;
+ }
+
vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate);
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);