Linux EFI development
 help / color / mirror / Atom feed
* Re: [PATCH] efi/riscv: Remove the useless failure return message print
From: Qiang Ma @ 2025-11-26  2:49 UTC (permalink / raw)
  To: ardb, Paul Walmsley
  Cc: ardb, palmer, aou, alex, linux-efi, linux-riscv, linux-kernel
In-Reply-To: <f9d632d5-22dc-8b14-8a70-37737a78f206@kernel.org>


在 2025/11/26 08:27, Paul Walmsley 写道:
> On Fri, 31 Oct 2025, Qiang Ma wrote:
>
>> In the efi_create_mapping() in arch/riscv/kernel/efi.c,
>> the return value is always 0, and this debug message
>> is unnecessary. So, remove it.
>>
>> Signed-off-by: Qiang Ma <maqianga@uniontech.com>
> Considering that Ard doesn't think efi_create_mapping() should be changed
> to remove the return value, and that the ARM version of this code retains
> the debug message, we should probably keep things the way they are.  But
> if you can get a Reviewed-by: or an Acked-by: from Ard, I'd take it.

Hi, Ard, what are your suggestions for this patch?

Could you add a Reviewed-by: or an Acked-by: to this patch?

>
>
> Thanks for your patch,
>
> - Paul
>
>


^ permalink raw reply

* Re: [PATCH] efi/riscv: Remove the useless failure return message print
From: Paul Walmsley @ 2025-11-26  0:27 UTC (permalink / raw)
  To: Qiang Ma; +Cc: ardb, pjw, palmer, aou, alex, linux-efi, linux-riscv,
	linux-kernel
In-Reply-To: <20251031024328.735161-1-maqianga@uniontech.com>

On Fri, 31 Oct 2025, Qiang Ma wrote:

> In the efi_create_mapping() in arch/riscv/kernel/efi.c,
> the return value is always 0, and this debug message
> is unnecessary. So, remove it.
> 
> Signed-off-by: Qiang Ma <maqianga@uniontech.com>

Considering that Ard doesn't think efi_create_mapping() should be changed 
to remove the return value, and that the ARM version of this code retains 
the debug message, we should probably keep things the way they are.  But 
if you can get a Reviewed-by: or an Acked-by: from Ard, I'd take it.


Thanks for your patch,

- Paul


^ permalink raw reply

* [RFC PATCH 4/4] mm: Add support for unaccepted memory hot-remove
From: Pratik R. Sampat @ 2025-11-25 17:57 UTC (permalink / raw)
  To: linux-mm, linux-coco, linux-efi, x86, linux-kernel
  Cc: tglx, mingo, bp, dave.hansen, kas, ardb, akpm, david, osalvador,
	thomas.lendacky, michael.roth, prsampat
In-Reply-To: <20251125175753.1428857-1-prsampat@amd.com>

Transition memory to shared during a hot-remove operation so that it can
be re-used by the hypervisor. During lazy acceptance, only memory that
was used has been accepted, therefore during hot-remove only mark pages
as shared that were previously accepted / made private.

Signed-off-by: Pratik R. Sampat <prsampat@amd.com>
---
 arch/x86/coco/sev/core.c                 | 23 +++++++++++++++
 arch/x86/include/asm/sev.h               |  2 ++
 arch/x86/include/asm/unaccepted_memory.h |  9 ++++++
 drivers/firmware/efi/unaccepted_memory.c | 37 ++++++++++++++++++++++++
 include/linux/mm.h                       |  7 +++++
 mm/memory_hotplug.c                      |  2 ++
 6 files changed, 80 insertions(+)

diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c
index a5c9615a6e0c..c05fc91d10a1 100644
--- a/arch/x86/coco/sev/core.c
+++ b/arch/x86/coco/sev/core.c
@@ -621,6 +621,29 @@ void snp_accept_memory(phys_addr_t start, phys_addr_t end)
 	set_pages_state(vaddr, npages, SNP_PAGE_STATE_PRIVATE, 0);
 }
 
+void snp_unaccept_memory(phys_addr_t start, phys_addr_t end)
+{
+	unsigned long vaddr, npages;
+
+	if (!cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
+		return;
+
+	vaddr = (unsigned long)__va(start);
+	npages = (end - start) >> PAGE_SHIFT;
+
+	/*
+	 * Hotplugged memory can be set to shared externally. Attempting to
+	 * re-share the memory (during hot-remove) will cause the pvalidate
+	 * operation to not make any changes to the RMP table triggering the
+	 * PVALIDATE_FAIL_NOUPDATE condition
+	 *
+	 * Since the memory hotplug case is unique, specify this intent so that
+	 * if the page is part of hotplugged memory a pvalidate rescind
+	 * operation is not performed
+	 */
+	set_pages_state(vaddr, npages, SNP_PAGE_STATE_SHARED, SNP_PSC_SHARED_TO_SHARED);
+}
+
 int snp_extend_hotplug_memory_state_bitmap(phys_addr_t start,
 					   unsigned long size,
 					   uint64_t unit_size)
diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
index eb605892645c..8f3c5b878fd7 100644
--- a/arch/x86/include/asm/sev.h
+++ b/arch/x86/include/asm/sev.h
@@ -547,6 +547,7 @@ void __noreturn snp_abort(void);
 void snp_dmi_setup(void);
 int snp_issue_svsm_attest_req(u64 call_id, struct svsm_call *call, struct svsm_attest_call *input);
 void snp_accept_memory(phys_addr_t start, phys_addr_t end);
+void snp_unaccept_memory(phys_addr_t start, phys_addr_t end);
 u64 snp_get_unsupported_features(u64 status);
 u64 sev_get_status(void);
 void sev_show_status(void);
@@ -639,6 +640,7 @@ static inline int snp_issue_svsm_attest_req(u64 call_id, struct svsm_call *call,
 	return -ENOTTY;
 }
 static inline void snp_accept_memory(phys_addr_t start, phys_addr_t end) { }
+static inline void snp_unaccept_memory(phys_addr_t start, phys_addr_t end) { }
 static inline u64 snp_get_unsupported_features(u64 status) { return 0; }
 static inline u64 sev_get_status(void) { return 0; }
 static inline void sev_show_status(void) { }
diff --git a/arch/x86/include/asm/unaccepted_memory.h b/arch/x86/include/asm/unaccepted_memory.h
index abdf5472de9e..ad392294b71b 100644
--- a/arch/x86/include/asm/unaccepted_memory.h
+++ b/arch/x86/include/asm/unaccepted_memory.h
@@ -18,6 +18,15 @@ static inline void arch_accept_memory(phys_addr_t start, phys_addr_t end)
 	}
 }
 
+static inline void arch_unaccept_memory(phys_addr_t start, phys_addr_t end)
+{
+	if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP)) {
+		snp_unaccept_memory(start, end);
+	} else {
+		panic("Cannot accept memory: unknown platform\n");
+	}
+}
+
 static inline struct efi_unaccepted_memory *efi_get_unaccepted_table(void)
 {
 	if (efi.unaccepted == EFI_INVALID_TABLE_ADDR)
diff --git a/drivers/firmware/efi/unaccepted_memory.c b/drivers/firmware/efi/unaccepted_memory.c
index 6796042a64aa..662cf0d6715f 100644
--- a/drivers/firmware/efi/unaccepted_memory.c
+++ b/drivers/firmware/efi/unaccepted_memory.c
@@ -301,6 +301,43 @@ int accept_hotplug_memory(phys_addr_t mem_range_start, unsigned long mem_range_s
 	return 0;
 }
 
+void unaccept_hotplug_memory(phys_addr_t mem_range_start, unsigned long mem_range_size)
+{
+	u64 unit_size, phys_base, bit_start, bit_end, addr;
+	struct efi_unaccepted_memory *unacc_tbl;
+	unsigned long flags, *bitmap;
+	phys_addr_t start, end;
+	int i;
+
+	unacc_tbl = efi_get_unaccepted_table();
+	if (!unacc_tbl)
+		return;
+
+	phys_base = unacc_tbl->phys_base;
+	unit_size = unacc_tbl->unit_size;
+
+	start = mem_range_start - phys_base;
+	end = (mem_range_start + mem_range_size) - phys_base;
+
+	bit_start = start / unit_size;
+	bit_end = end / unit_size;
+
+	/* Only unaccept memory that was previously accepted in the range */
+	for (i = bit_start; i < bit_end; i++) {
+		spin_lock_irqsave(&unaccepted_memory_lock, flags);
+		bitmap = efi_get_unaccepted_bitmap();
+		if (!bitmap || test_bit(i, bitmap)) {
+			spin_unlock_irqrestore(&unaccepted_memory_lock, flags);
+			continue;
+		}
+
+		addr = phys_base + i * unit_size;
+
+		arch_unaccept_memory(addr, addr + unit_size);
+		spin_unlock_irqrestore(&unaccepted_memory_lock, flags);
+	}
+}
+
 #ifdef CONFIG_PROC_VMCORE
 static bool unaccepted_memory_vmcore_pfn_is_ram(struct vmcore_cb *cb,
 						unsigned long pfn)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index bb43876e6c47..34d48693dc86 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -4079,6 +4079,8 @@ bool range_contains_unaccepted_memory(phys_addr_t start, unsigned long size);
 void accept_memory(phys_addr_t start, unsigned long size);
 int accept_hotplug_memory(phys_addr_t mem_range_start,
 			  unsigned long mem_range_size);
+void unaccept_hotplug_memory(phys_addr_t mem_range_start,
+			     unsigned long mem_range_size);
 bool mm_lazy_accept_enabled(void);
 
 #else
@@ -4099,6 +4101,11 @@ static inline int accept_hotplug_memory(phys_addr_t mem_range_start,
 	return 0;
 }
 
+static inline void unaccept_hotplug_memory(phys_addr_t mem_range_start,
+					   unsigned long mem_range_size)
+{
+}
+
 static inline bool mm_lazy_accept_enabled(void) { return false; }
 
 #endif
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index bf8086682b66..0b14b14e53fe 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -2254,6 +2254,8 @@ static int try_remove_memory(u64 start, u64 size)
 
 	mem_hotplug_begin();
 
+	unaccept_hotplug_memory(start, size);
+
 	rc = memory_blocks_have_altmaps(start, size);
 	if (rc < 0) {
 		mem_hotplug_done();
-- 
2.51.1


^ permalink raw reply related

* [RFC PATCH 3/4] x86/sev: Introduce hotplug-aware SNP page state validation
From: Pratik R. Sampat @ 2025-11-25 17:57 UTC (permalink / raw)
  To: linux-mm, linux-coco, linux-efi, x86, linux-kernel
  Cc: tglx, mingo, bp, dave.hansen, kas, ardb, akpm, david, osalvador,
	thomas.lendacky, michael.roth, prsampat
In-Reply-To: <20251125175753.1428857-1-prsampat@amd.com>

When hot-removing memory in a SEV-SNP environment, pages must be set to
shared state so they can be reused by the hypervisor. This also applies
when memory is intended to be hotplugged back in later, as those pages
will need to be re-accepted after crossing the trust boundary.

However, memory can already be set to shared state externally. In such
cases, the pvalidate rescind operation will not change the validated bit
in the RMP table, setting the carry flag and causing the guest to
terminate.

Since memory hotplug is arguably unique, introduce a guest-maintained
memory state tracking structure that maintains a bitmap to track the
state (private vs shared) of all hotplugged memory supplemented with a
flag to indicate intent. This allows for memory that is already marked
as shared in the hotplug bitmap to avoid performing the pvalidate
rescind operation. Additionally, tracking page state changes from the
guest's perspective, enables the detection of inconsistencies if the
hypervisor changes states unexpectedly. For example, if the guest bitmap
reports memory as private but the hypervisor has already changed the RMP
state to shared, the guest detects this inconsistency when attempting to
share the memory and terminate rather than skipping over the pvalidate
rescind operation.

Signed-off-by: Pratik R. Sampat <prsampat@amd.com>
---
 arch/x86/coco/sev/core.c                 | 104 +++++++++++++++++++++--
 arch/x86/include/asm/sev.h               |  32 +++++++
 arch/x86/include/asm/unaccepted_memory.h |  13 +++
 drivers/firmware/efi/unaccepted_memory.c |   2 +-
 4 files changed, 143 insertions(+), 8 deletions(-)

diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c
index 14ef5908fb27..a5c9615a6e0c 100644
--- a/arch/x86/coco/sev/core.c
+++ b/arch/x86/coco/sev/core.c
@@ -46,6 +46,8 @@
 #include <asm/cmdline.h>
 #include <asm/msr.h>
 
+struct snp_hotplug_memory *snp_hp_mem;
+
 /* AP INIT values as documented in the APM2  section "Processor Initialization State" */
 #define AP_INIT_CS_LIMIT		0xffff
 #define AP_INIT_DS_LIMIT		0xffff
@@ -453,9 +455,54 @@ static int vmgexit_psc(struct ghcb *ghcb, struct snp_psc_desc *desc)
 	return ret;
 }
 
+static bool snp_hotplug_state_shared(unsigned long vaddr)
+{
+	phys_addr_t paddr = __pa(vaddr);
+	u64 hotplug_bit;
+
+	if (!snp_is_hotplug_memory(paddr))
+		return false;
+
+	hotplug_bit = (paddr - snp_hp_mem->phys_base) / snp_hp_mem->unit_size;
+
+	return !test_bit(hotplug_bit, snp_hp_mem->bitmap);
+}
+
+static void snp_set_hotplug_bit(unsigned long vaddr, bool private)
+{
+	phys_addr_t paddr = __pa(vaddr);
+	u64 hotplug_bit;
+
+	if (!snp_is_hotplug_memory(paddr))
+		return;
+
+	hotplug_bit = (paddr - snp_hp_mem->phys_base) / snp_hp_mem->unit_size;
+	if (private)
+		set_bit(hotplug_bit, snp_hp_mem->bitmap);
+	else
+		clear_bit(hotplug_bit, snp_hp_mem->bitmap);
+}
+
+static void set_hotplug_pages_state(struct snp_psc_desc *desc)
+{
+	struct psc_entry *e;
+	unsigned long vaddr;
+	bool op;
+	int i;
+
+	for (i = 0; i <= desc->hdr.end_entry; i++) {
+		e = &desc->entries[i];
+		vaddr = (unsigned long)pfn_to_kaddr(e->gfn);
+		op = e->operation == SNP_PAGE_STATE_PRIVATE;
+
+		snp_set_hotplug_bit(vaddr, op);
+	}
+}
+
 static unsigned long __set_pages_state(struct snp_psc_desc *data, unsigned long vaddr,
-				       unsigned long vaddr_end, int op)
+				       unsigned long vaddr_end, int op, u8 psc_flags)
 {
+	unsigned long vaddr_base;
 	struct ghcb_state state;
 	bool use_large_entry;
 	struct psc_hdr *hdr;
@@ -465,6 +512,7 @@ static unsigned long __set_pages_state(struct snp_psc_desc *data, unsigned long
 	struct ghcb *ghcb;
 	int i;
 
+	vaddr_base = vaddr;
 	hdr = &data->hdr;
 	e = data->entries;
 
@@ -499,7 +547,8 @@ static unsigned long __set_pages_state(struct snp_psc_desc *data, unsigned long
 	}
 
 	/* Page validation must be rescinded before changing to shared */
-	if (op == SNP_PAGE_STATE_SHARED)
+	if (op == SNP_PAGE_STATE_SHARED &&
+	    !(snp_hotplug_state_shared(vaddr_base) && (psc_flags & SNP_PSC_SHARED_TO_SHARED)))
 		pvalidate_pages(data);
 
 	local_irq_save(flags);
@@ -522,10 +571,12 @@ static unsigned long __set_pages_state(struct snp_psc_desc *data, unsigned long
 	if (op == SNP_PAGE_STATE_PRIVATE)
 		pvalidate_pages(data);
 
+	set_hotplug_pages_state(data);
+
 	return vaddr;
 }
 
-static void set_pages_state(unsigned long vaddr, unsigned long npages, int op)
+static void set_pages_state(unsigned long vaddr, unsigned long npages, int op, u8 psc_flags)
 {
 	struct snp_psc_desc desc;
 	unsigned long vaddr_end;
@@ -538,7 +589,7 @@ static void set_pages_state(unsigned long vaddr, unsigned long npages, int op)
 	vaddr_end = vaddr + (npages << PAGE_SHIFT);
 
 	while (vaddr < vaddr_end)
-		vaddr = __set_pages_state(&desc, vaddr, vaddr_end, op);
+		vaddr = __set_pages_state(&desc, vaddr, vaddr_end, op, psc_flags);
 }
 
 void snp_set_memory_shared(unsigned long vaddr, unsigned long npages)
@@ -546,7 +597,7 @@ void snp_set_memory_shared(unsigned long vaddr, unsigned long npages)
 	if (!cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
 		return;
 
-	set_pages_state(vaddr, npages, SNP_PAGE_STATE_SHARED);
+	set_pages_state(vaddr, npages, SNP_PAGE_STATE_SHARED, 0);
 }
 
 void snp_set_memory_private(unsigned long vaddr, unsigned long npages)
@@ -554,7 +605,7 @@ void snp_set_memory_private(unsigned long vaddr, unsigned long npages)
 	if (!cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
 		return;
 
-	set_pages_state(vaddr, npages, SNP_PAGE_STATE_PRIVATE);
+	set_pages_state(vaddr, npages, SNP_PAGE_STATE_PRIVATE, 0);
 }
 
 void snp_accept_memory(phys_addr_t start, phys_addr_t end)
@@ -567,7 +618,46 @@ void snp_accept_memory(phys_addr_t start, phys_addr_t end)
 	vaddr = (unsigned long)__va(start);
 	npages = (end - start) >> PAGE_SHIFT;
 
-	set_pages_state(vaddr, npages, SNP_PAGE_STATE_PRIVATE);
+	set_pages_state(vaddr, npages, SNP_PAGE_STATE_PRIVATE, 0);
+}
+
+int snp_extend_hotplug_memory_state_bitmap(phys_addr_t start,
+					   unsigned long size,
+					   uint64_t unit_size)
+{
+	u64 hp_mem_size = DIV_ROUND_UP(size, unit_size * BITS_PER_BYTE);
+
+	if (snp_hp_mem) {
+		u64 old_size = snp_hp_mem->size;
+		unsigned long *bitmap;
+
+		bitmap = krealloc(snp_hp_mem->bitmap, hp_mem_size, GFP_KERNEL);
+		if (!bitmap)
+			return -ENOMEM;
+
+		memset(bitmap + old_size, 0, hp_mem_size - old_size);
+		snp_hp_mem->size = hp_mem_size;
+		snp_hp_mem->bitmap = bitmap;
+
+		return 0;
+	}
+
+	snp_hp_mem = kzalloc(sizeof(*snp_hp_mem), GFP_KERNEL);
+	if (!snp_hp_mem)
+		return -ENOMEM;
+
+	snp_hp_mem->bitmap = kzalloc(hp_mem_size, GFP_KERNEL);
+	if (!snp_hp_mem->bitmap) {
+		kfree(snp_hp_mem);
+		return -ENOMEM;
+	}
+
+	snp_hp_mem->phys_base = start;
+	snp_hp_mem->phys_end = start + hp_mem_size;
+	snp_hp_mem->size = hp_mem_size;
+	snp_hp_mem->unit_size = unit_size;
+
+	return 0;
 }
 
 static int vmgexit_ap_control(u64 event, struct sev_es_save_area *vmsa, u32 apic_id)
diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
index 465b19fd1a2d..eb605892645c 100644
--- a/arch/x86/include/asm/sev.h
+++ b/arch/x86/include/asm/sev.h
@@ -464,6 +464,38 @@ static __always_inline void sev_es_nmi_complete(void)
 extern int __init sev_es_efi_map_ghcbs_cas(pgd_t *pgd);
 extern void sev_enable(struct boot_params *bp);
 
+#define SNP_PSC_SHARED_TO_SHARED	0x1
+
+struct snp_hotplug_memory {
+	u64 phys_base;
+	u64 phys_end;
+	u32 unit_size;
+	u64 size;
+	/* bitmap bit unset: shared, set: private */
+	unsigned long *bitmap;
+};
+
+extern struct snp_hotplug_memory *snp_hp_mem;
+
+#ifdef CONFIG_UNACCEPTED_MEMORY
+int snp_extend_hotplug_memory_state_bitmap(phys_addr_t start,
+					   unsigned long size,
+					   uint64_t unit_size);
+static inline bool snp_is_hotplug_memory(phys_addr_t paddr)
+{
+	return snp_hp_mem && paddr >= snp_hp_mem->phys_base && paddr < snp_hp_mem->phys_end;
+}
+#else /* !CONFIG_UNACCEPTED_MEMORY */
+static inline int snp_extend_hotplug_memory_state_bitmap(phys_addr_t start,
+							 unsigned long size,
+							 uint64_t unit_size)
+{
+	return 0;
+}
+
+static inline bool snp_is_hotplug_memory(phys_addr_t paddr) { return false; }
+#endif
+
 /*
  * RMPADJUST modifies the RMP permissions of a page of a lesser-
  * privileged (numerically higher) VMPL.
diff --git a/arch/x86/include/asm/unaccepted_memory.h b/arch/x86/include/asm/unaccepted_memory.h
index 5da80e68d718..abdf5472de9e 100644
--- a/arch/x86/include/asm/unaccepted_memory.h
+++ b/arch/x86/include/asm/unaccepted_memory.h
@@ -33,4 +33,17 @@ static inline unsigned long *efi_get_unaccepted_bitmap(void)
 		return NULL;
 	return __va(unaccepted->bitmap);
 }
+
+static inline int arch_set_unaccepted_mem_state(phys_addr_t start, unsigned long size)
+{
+	struct efi_unaccepted_memory *unaccepted = efi_get_unaccepted_table();
+
+	if (!unaccepted)
+		return -EIO;
+
+	if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
+		return snp_extend_hotplug_memory_state_bitmap(start, size, unaccepted->unit_size);
+
+	return 0;
+}
 #endif
diff --git a/drivers/firmware/efi/unaccepted_memory.c b/drivers/firmware/efi/unaccepted_memory.c
index 8537812346e2..6796042a64aa 100644
--- a/drivers/firmware/efi/unaccepted_memory.c
+++ b/drivers/firmware/efi/unaccepted_memory.c
@@ -281,7 +281,7 @@ static int extend_unaccepted_bitmap(phys_addr_t mem_range_start,
 	unacc_tbl->bitmap = (unsigned long *)__pa(new_bitmap);
 	spin_unlock_irqrestore(&unaccepted_memory_lock, flags);
 
-	return 0;
+	return arch_set_unaccepted_mem_state(mem_range_start, mem_range_size);
 }
 
 int accept_hotplug_memory(phys_addr_t mem_range_start, unsigned long mem_range_size)
-- 
2.51.1


^ permalink raw reply related

* [RFC PATCH 2/4] mm: Add support for unaccepted memory hotplug
From: Pratik R. Sampat @ 2025-11-25 17:57 UTC (permalink / raw)
  To: linux-mm, linux-coco, linux-efi, x86, linux-kernel
  Cc: tglx, mingo, bp, dave.hansen, kas, ardb, akpm, david, osalvador,
	thomas.lendacky, michael.roth, prsampat
In-Reply-To: <20251125175753.1428857-1-prsampat@amd.com>

The unaccepted memory structure currently only supports accepting memory
present at boot time. The unaccepted table uses a fixed-size bitmap
reserved in memblock based on the initial memory layout, preventing
dynamic addition of memory ranges after boot. This causes guest
termination when memory is hot-added in a secure virtual machine due to
accessing pages that have not transitioned to private before use.

Extend the unaccepted memory framework to handle hotplugged memory by
dynamically managing the unaccepted bitmap. Allocate a new bitmap when
hotplugged ranges exceed the reserved bitmap capacity and switch to
kernel-managed allocation.

Hotplugged memory also follows the same acceptance policy using the
accept_memory=[eager|lazy] kernel parameter to accept memory either
up-front when added or before first use.

Signed-off-by: Pratik R. Sampat <prsampat@amd.com>
---
 arch/x86/boot/compressed/efi.h                |  1 +
 .../firmware/efi/libstub/unaccepted_memory.c  |  1 +
 drivers/firmware/efi/unaccepted_memory.c      | 83 +++++++++++++++++++
 include/linux/efi.h                           |  1 +
 include/linux/mm.h                            | 11 +++
 mm/memory_hotplug.c                           |  7 ++
 mm/page_alloc.c                               |  2 +
 7 files changed, 106 insertions(+)

diff --git a/arch/x86/boot/compressed/efi.h b/arch/x86/boot/compressed/efi.h
index 4f7027f33def..a220a1966cae 100644
--- a/arch/x86/boot/compressed/efi.h
+++ b/arch/x86/boot/compressed/efi.h
@@ -102,6 +102,7 @@ struct efi_unaccepted_memory {
 	u32 unit_size;
 	u64 phys_base;
 	u64 size;
+	bool mem_reserved;
 	unsigned long *bitmap;
 };
 
diff --git a/drivers/firmware/efi/libstub/unaccepted_memory.c b/drivers/firmware/efi/libstub/unaccepted_memory.c
index c1370fc14555..b16bd61c12bf 100644
--- a/drivers/firmware/efi/libstub/unaccepted_memory.c
+++ b/drivers/firmware/efi/libstub/unaccepted_memory.c
@@ -83,6 +83,7 @@ efi_status_t allocate_unaccepted_bitmap(__u32 nr_desc,
 	unaccepted_table->unit_size = EFI_UNACCEPTED_UNIT_SIZE;
 	unaccepted_table->phys_base = unaccepted_start;
 	unaccepted_table->size = bitmap_size;
+	unaccepted_table->mem_reserved = true;
 	memset(unaccepted_table->bitmap, 0, bitmap_size);
 
 	status = efi_bs_call(install_configuration_table,
diff --git a/drivers/firmware/efi/unaccepted_memory.c b/drivers/firmware/efi/unaccepted_memory.c
index 4479aad258f8..8537812346e2 100644
--- a/drivers/firmware/efi/unaccepted_memory.c
+++ b/drivers/firmware/efi/unaccepted_memory.c
@@ -218,6 +218,89 @@ bool range_contains_unaccepted_memory(phys_addr_t start, unsigned long size)
 	return ret;
 }
 
+static int extend_unaccepted_bitmap(phys_addr_t mem_range_start,
+				    unsigned long mem_range_size)
+{
+	struct efi_unaccepted_memory *unacc_tbl;
+	unsigned long *old_bitmap, *new_bitmap;
+	phys_addr_t start, end, mem_range_end;
+	u64 phys_base, size, unit_size;
+	unsigned long flags;
+
+	unacc_tbl = efi_get_unaccepted_table();
+	if (!unacc_tbl || !unacc_tbl->unit_size)
+		return -EIO;
+
+	unit_size = unacc_tbl->unit_size;
+	phys_base = unacc_tbl->phys_base;
+
+	mem_range_end = round_up(mem_range_start + mem_range_size, unit_size);
+	size = DIV_ROUND_UP(mem_range_end - phys_base, unit_size * BITS_PER_BYTE);
+
+	/* Translate to offsets from the beginning of the bitmap */
+	start = mem_range_start - phys_base;
+	end = mem_range_end - phys_base;
+
+	old_bitmap = efi_get_unaccepted_bitmap();
+	if (!old_bitmap)
+		return -EIO;
+
+	/* If the bitmap is already large enough, just set the bits */
+	if (unacc_tbl->size >= size) {
+		spin_lock_irqsave(&unaccepted_memory_lock, flags);
+		bitmap_set(old_bitmap, start / unit_size, (end - start) / unit_size);
+		spin_unlock_irqrestore(&unaccepted_memory_lock, flags);
+
+		return 0;
+	}
+
+	/* Reserved memblocks cannot be extended so allocate a new bitmap */
+	if (unacc_tbl->mem_reserved) {
+		new_bitmap = kzalloc(size, GFP_KERNEL);
+		if (!new_bitmap)
+			return -ENOMEM;
+
+		spin_lock_irqsave(&unaccepted_memory_lock, flags);
+		memcpy(new_bitmap, old_bitmap, unacc_tbl->size);
+		unacc_tbl->mem_reserved = false;
+		free_reserved_area(old_bitmap, old_bitmap + unacc_tbl->size, -1, NULL);
+		spin_unlock_irqrestore(&unaccepted_memory_lock, flags);
+	} else {
+		new_bitmap = krealloc(old_bitmap, size, GFP_KERNEL);
+		if (!new_bitmap)
+			return -ENOMEM;
+
+		/* Zero the bitmap from the range it was extended from */
+		memset(new_bitmap + unacc_tbl->size, 0, size - unacc_tbl->size);
+	}
+
+	bitmap_set(new_bitmap, start / unit_size, (end - start) / unit_size);
+
+	spin_lock_irqsave(&unaccepted_memory_lock, flags);
+	unacc_tbl->size = size;
+	unacc_tbl->bitmap = (unsigned long *)__pa(new_bitmap);
+	spin_unlock_irqrestore(&unaccepted_memory_lock, flags);
+
+	return 0;
+}
+
+int accept_hotplug_memory(phys_addr_t mem_range_start, unsigned long mem_range_size)
+{
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_UNACCEPTED_MEMORY))
+		return 0;
+
+	ret = extend_unaccepted_bitmap(mem_range_start, mem_range_size);
+	if (ret)
+		return ret;
+
+	if (!mm_lazy_accept_enabled())
+		accept_memory(mem_range_start, mem_range_size);
+
+	return 0;
+}
+
 #ifdef CONFIG_PROC_VMCORE
 static bool unaccepted_memory_vmcore_pfn_is_ram(struct vmcore_cb *cb,
 						unsigned long pfn)
diff --git a/include/linux/efi.h b/include/linux/efi.h
index a74b393c54d8..1021eb78388f 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -545,6 +545,7 @@ struct efi_unaccepted_memory {
 	u32 unit_size;
 	u64 phys_base;
 	u64 size;
+	bool mem_reserved;
 	unsigned long *bitmap;
 };
 
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 1ae97a0b8ec7..bb43876e6c47 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -4077,6 +4077,9 @@ int set_anon_vma_name(unsigned long addr, unsigned long size,
 
 bool range_contains_unaccepted_memory(phys_addr_t start, unsigned long size);
 void accept_memory(phys_addr_t start, unsigned long size);
+int accept_hotplug_memory(phys_addr_t mem_range_start,
+			  unsigned long mem_range_size);
+bool mm_lazy_accept_enabled(void);
 
 #else
 
@@ -4090,6 +4093,14 @@ static inline void accept_memory(phys_addr_t start, unsigned long size)
 {
 }
 
+static inline int accept_hotplug_memory(phys_addr_t mem_range_start,
+					unsigned long mem_range_size)
+{
+	return 0;
+}
+
+static inline bool mm_lazy_accept_enabled(void) { return false; }
+
 #endif
 
 static inline bool pfn_is_unaccepted_memory(unsigned long pfn)
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 74318c787715..bf8086682b66 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1581,6 +1581,13 @@ int add_memory_resource(int nid, struct resource *res, mhp_t mhp_flags)
 	if (!strcmp(res->name, "System RAM"))
 		firmware_map_add_hotplug(start, start + size, "System RAM");
 
+	ret = accept_hotplug_memory(start, size);
+	if (ret) {
+		remove_memory_block_devices(start, size);
+		arch_remove_memory(start, size, params.altmap);
+		goto error;
+	}
+
 	/* device_online() will take the lock when calling online_pages() */
 	mem_hotplug_done();
 
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index d1d037f97c5f..d0c298dcaf9d 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -7331,6 +7331,8 @@ bool has_managed_dma(void)
 
 static bool lazy_accept = true;
 
+bool mm_lazy_accept_enabled(void) { return lazy_accept; }
+
 static int __init accept_memory_parse(char *p)
 {
 	if (!strcmp(p, "lazy")) {
-- 
2.51.1


^ permalink raw reply related

* [RFC PATCH 1/4] efi/libstub: Decouple memory bitmap from the unaccepted table
From: Pratik R. Sampat @ 2025-11-25 17:57 UTC (permalink / raw)
  To: linux-mm, linux-coco, linux-efi, x86, linux-kernel
  Cc: tglx, mingo, bp, dave.hansen, kas, ardb, akpm, david, osalvador,
	thomas.lendacky, michael.roth, prsampat
In-Reply-To: <20251125175753.1428857-1-prsampat@amd.com>

Memory hotplug in secure environments requires the unaccepted memory
bitmap to grow as new memory is added. Currently, the bitmap is
implemented as a flexible array member at the end of struct
efi_unaccepted_memory, which is reserved by memblock at boot and cannot
be resized without reallocating the entire structure.

Replace the flexible array member with a pointer. This allows the bitmap
to be allocated and managed independently from the unaccepted memory
table, enabling dynamic growth to support memory hotplug.

Signed-off-by: Pratik R. Sampat <prsampat@amd.com>
---
 arch/x86/boot/compressed/efi.h                |  2 +-
 arch/x86/include/asm/unaccepted_memory.h      |  9 +++++++++
 .../firmware/efi/libstub/unaccepted_memory.c  | 11 ++++++++++-
 drivers/firmware/efi/unaccepted_memory.c      | 19 ++++++++++++++-----
 include/linux/efi.h                           |  2 +-
 5 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/arch/x86/boot/compressed/efi.h b/arch/x86/boot/compressed/efi.h
index b22300970f97..4f7027f33def 100644
--- a/arch/x86/boot/compressed/efi.h
+++ b/arch/x86/boot/compressed/efi.h
@@ -102,7 +102,7 @@ struct efi_unaccepted_memory {
 	u32 unit_size;
 	u64 phys_base;
 	u64 size;
-	unsigned long bitmap[];
+	unsigned long *bitmap;
 };
 
 static inline int efi_guidcmp (efi_guid_t left, efi_guid_t right)
diff --git a/arch/x86/include/asm/unaccepted_memory.h b/arch/x86/include/asm/unaccepted_memory.h
index f5937e9866ac..5da80e68d718 100644
--- a/arch/x86/include/asm/unaccepted_memory.h
+++ b/arch/x86/include/asm/unaccepted_memory.h
@@ -24,4 +24,13 @@ static inline struct efi_unaccepted_memory *efi_get_unaccepted_table(void)
 		return NULL;
 	return __va(efi.unaccepted);
 }
+
+static inline unsigned long *efi_get_unaccepted_bitmap(void)
+{
+	struct efi_unaccepted_memory *unaccepted = efi_get_unaccepted_table();
+
+	if (!unaccepted)
+		return NULL;
+	return __va(unaccepted->bitmap);
+}
 #endif
diff --git a/drivers/firmware/efi/libstub/unaccepted_memory.c b/drivers/firmware/efi/libstub/unaccepted_memory.c
index 757dbe734a47..c1370fc14555 100644
--- a/drivers/firmware/efi/libstub/unaccepted_memory.c
+++ b/drivers/firmware/efi/libstub/unaccepted_memory.c
@@ -63,13 +63,22 @@ efi_status_t allocate_unaccepted_bitmap(__u32 nr_desc,
 				   EFI_UNACCEPTED_UNIT_SIZE * BITS_PER_BYTE);
 
 	status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY,
-			     sizeof(*unaccepted_table) + bitmap_size,
+			     sizeof(*unaccepted_table),
 			     (void **)&unaccepted_table);
 	if (status != EFI_SUCCESS) {
 		efi_err("Failed to allocate unaccepted memory config table\n");
 		return status;
 	}
 
+	status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY,
+			     bitmap_size,
+			     (void **)&unaccepted_table->bitmap);
+	if (status != EFI_SUCCESS) {
+		efi_bs_call(free_pool, unaccepted_table);
+		efi_err("Failed to allocate unaccepted memory bitmap\n");
+		return status;
+	}
+
 	unaccepted_table->version = 1;
 	unaccepted_table->unit_size = EFI_UNACCEPTED_UNIT_SIZE;
 	unaccepted_table->phys_base = unaccepted_start;
diff --git a/drivers/firmware/efi/unaccepted_memory.c b/drivers/firmware/efi/unaccepted_memory.c
index c2c067eff634..4479aad258f8 100644
--- a/drivers/firmware/efi/unaccepted_memory.c
+++ b/drivers/firmware/efi/unaccepted_memory.c
@@ -36,7 +36,7 @@ void accept_memory(phys_addr_t start, unsigned long size)
 	unsigned long range_start, range_end;
 	struct accept_range range, *entry;
 	phys_addr_t end = start + size;
-	unsigned long flags;
+	unsigned long flags, *bitmap;
 	u64 unit_size;
 
 	unaccepted = efi_get_unaccepted_table();
@@ -124,8 +124,12 @@ void accept_memory(phys_addr_t start, unsigned long size)
 	list_add(&range.list, &accepting_list);
 
 	range_start = range.start;
-	for_each_set_bitrange_from(range_start, range_end, unaccepted->bitmap,
-				   range.end) {
+
+	bitmap = efi_get_unaccepted_bitmap();
+	if (!bitmap)
+		return;
+
+	for_each_set_bitrange_from(range_start, range_end, bitmap, range.end) {
 		unsigned long phys_start, phys_end;
 		unsigned long len = range_end - range_start;
 
@@ -147,7 +151,7 @@ void accept_memory(phys_addr_t start, unsigned long size)
 		arch_accept_memory(phys_start, phys_end);
 
 		spin_lock(&unaccepted_memory_lock);
-		bitmap_clear(unaccepted->bitmap, range_start, len);
+		bitmap_clear(bitmap, range_start, len);
 	}
 
 	list_del(&range.list);
@@ -197,7 +201,12 @@ bool range_contains_unaccepted_memory(phys_addr_t start, unsigned long size)
 
 	spin_lock_irqsave(&unaccepted_memory_lock, flags);
 	while (start < end) {
-		if (test_bit(start / unit_size, unaccepted->bitmap)) {
+		unsigned long *bitmap = efi_get_unaccepted_bitmap();
+
+		if (!bitmap)
+			break;
+
+		if (test_bit(start / unit_size, bitmap)) {
 			ret = true;
 			break;
 		}
diff --git a/include/linux/efi.h b/include/linux/efi.h
index a98cc39e7aaa..a74b393c54d8 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -545,7 +545,7 @@ struct efi_unaccepted_memory {
 	u32 unit_size;
 	u64 phys_base;
 	u64 size;
-	unsigned long bitmap[];
+	unsigned long *bitmap;
 };
 
 /*
-- 
2.51.1


^ permalink raw reply related

* [RFC PATCH 0/4] SEV-SNP Unaccepted Memory Hotplug
From: Pratik R. Sampat @ 2025-11-25 17:57 UTC (permalink / raw)
  To: linux-mm, linux-coco, linux-efi, x86, linux-kernel
  Cc: tglx, mingo, bp, dave.hansen, kas, ardb, akpm, david, osalvador,
	thomas.lendacky, michael.roth, prsampat

Guest memory hot-plug/remove via the QEMU monitor is used by virtual
machines to dynamically scale the memory capacity of a system with
virtually zero downtime to the guest. For confidential VMs, memory has
to be first accepted before it can be used.

The unaccepted memory feature provides a mechanism to accept memory
either up-front or right before it is needed. The unaccepted table that
tracks this information is allocated and memory block reserved at boot
time. For memory hotplug, this means the table cannot be updated to
track additional regions and accept them as the guest physical memory
grows.

This proof-of-concept series extends the unaccepted memory
infrastructure to support memory hotplug and hot-unplug on the SNP
platform. On a high-level, it does so by decoupling the memory bitmap
from the unaccepted table so that kernel can manage bitmap when memory
is added. For hot-remove, it reverts the page states so that the
hypervisor can reuse that memory. Hot-remove also presents a unique
scenario where the memory we attempt to share can already be in a shared
state set externally which can cause pvalidation on the platform to fail
since no updates were made to the validated bit. Handle this case by
tracking the state of hotplugged memory within the guest and disallow
pvalidate operations on the same state.

Usage (for SNP guests)
----------------------
Step1: Spawn a QEMU SNP guest with the additional parameter of slots and
maximum possible memory, along with the initial memory as below:
"-m X,slots=Y,maxmem=Z".

Use the "accept_memory=[eager|lazy]" kernel command-line parameter to
specify whether hotplugged memory should be accepted immediately upon
addition or only when first accessed. By default, lazy acceptance is
used.

Step2: Once the guest is booted, launch the qemu monitor and hotplug
the memory as follows:
(qemu) object_add memory-backend-memfd,id=mem1,size=1G
(qemu) device_add pc-dimm,id=dimm1,memdev=mem1

Step3: If using auto-onlining by either:
    a) echo online > /sys/devices/system/memory/auto_online_blocks, OR
    b) enable CONFIG_MHP_DEFAULT_ONLINE_TYPE_* while compiling kernel
Memory should show up automatically.

Otherwise, memory can also be onlined by echoing 1 to the newly added
blocks in: /sys/devices/system/memory/memoryXX/online

Step4: If accept_memory is set to eager, all memory is accepted
immediately. Otherwise, memory is accepted on access. For the latter,
acceptance can be triggered by simply running a program such as
stress-ng that requests enough memory to cover the newly allocated
hotplugged regions.

$ stress-ng --vm 1 --vm-bytes={X}G -t {T}s

Step5: memory can be hot-removed using the qemu monitor using:
(qemu) device_remove dimm1
(qemu) object_remove mem1

Tip: Enable the kvm_convert_memory event in QEMU to observe memory
conversions between private and shared during hotplug/remove.

The series is based on
        git.kernel.org/pub/scm/virt/kvm/kvm.git next

Comments and feedback appreciated!

Pratik R. Sampat (4):
  efi/libstub: Decouple memory bitmap from the unaccepted table
  mm: Add support for unaccepted memory hotplug
  x86/sev: Introduce hotplug-aware SNP page state validation
  mm: Add support for unaccepted memory hot-remove

 arch/x86/boot/compressed/efi.h                |   3 +-
 arch/x86/coco/sev/core.c                      | 127 +++++++++++++++-
 arch/x86/include/asm/sev.h                    |  34 +++++
 arch/x86/include/asm/unaccepted_memory.h      |  31 ++++
 .../firmware/efi/libstub/unaccepted_memory.c  |  12 +-
 drivers/firmware/efi/unaccepted_memory.c      | 139 +++++++++++++++++-
 include/linux/efi.h                           |   3 +-
 include/linux/mm.h                            |  18 +++
 mm/memory_hotplug.c                           |   9 ++
 mm/page_alloc.c                               |   2 +
 10 files changed, 363 insertions(+), 15 deletions(-)

-- 
2.51.1


^ permalink raw reply

* Re: [REGRESSION] Re: [PATCH v2 22/50] convert efivarfs
From: Christian Brauner @ 2025-11-25  9:00 UTC (permalink / raw)
  To: Chris Bainbridge
  Cc: James Bottomley, Ard Biesheuvel, Al Viro, linux-fsdevel, torvalds,
	jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi,
	ocfs2-devel, kees, rostedt, gregkh, linux-usb, paul, casey,
	linuxppc-dev, john.johansen, selinux, borntraeger, bpf,
	regressions
In-Reply-To: <aR4zisdeorFTTwOv@debian.local>

On Wed, Nov 19, 2025 at 09:15:54PM +0000, Chris Bainbridge wrote:
> On Wed, Nov 05, 2025 at 02:43:34PM +0100, Christian Brauner wrote:
> > > > > And suspend/resume works just fine with freeze/thaw. See commit
> > > > > eacfbf74196f ("power: freeze filesystems during suspend/resume")
> > > > > which implements exactly that.
> > > > > 
> > > > > The reason this didn't work for you is very likely:
> > > > > 
> > > > > cat /sys/power/freeze_filesystems
> > > > > 0
> > > > > 
> > > > > which you must set to 1.
> > > > 
> > > > Actually, no, that's not correct.  The efivarfs freeze/thaw logic must
> > > > run unconditionally regardless of this setting to fix the systemd bug,
> > > > so all the variable resyncing is done in the thaw call, which isn't
> > > > conditioned on the above (or at least it shouldn't be).
> > > 
> > > It is conditioned on the above currently but we can certainly fix it
> > > easily to not be.
> > 
> > Something like the appended patch would do it.
> 
> > >From 1f9dc293cebb10b18d9ec8e01b60c014664c98ab Mon Sep 17 00:00:00 2001
> > From: Christian Brauner <brauner@kernel.org>
> > Date: Wed, 5 Nov 2025 14:39:45 +0100
> > Subject: [PATCH] power: always freeze efivarfs
> > 
> > The efivarfs filesystems must always be frozen and thawed to resync
> > variable state. Make it so.
> > 
> > Signed-off-by: Christian Brauner <brauner@kernel.org>
> 
> I bisected some intermittent (44% chance of occuring on any given
> suspend) lock warnings on suspend to this commit:
> 
> a3f8f8662771285511ae26c4c8d3ba1cd22159b9 power: always freeze efivarfs
> 
> Reproducer: `for x in {1..20}; do systemctl suspend; sleep 5; done`

This is very likely a false-positive triggered by:

  #ifdef CONFIG_LOCKDEP
          /*
           * It's dangerous to freeze with locks held; there be dragons there.
           */
          if (!(state & __TASK_FREEZABLE_UNSAFE))
                  WARN_ON_ONCE(debug_locks && p->lockdep_depth);
  #endif

in __set_task_frozen(). When a filesystem is frozen we'll acquire 

percpu_down_read_freezable(sb->s_writers.rw_sem + level - 1, true);

at some point. And while that fs is frozen that rw_sem will remain held.
__set_task_frozen()'s lockdep annotation doesn't yet know what to do
with such tasks and then complains about them when lockdep is enabled.
It should have an exception for the suspend path here specifically.
IIRC, we asked peterz how to handle this a couple of months ago. It
seems we didn't reach a conclusion. It's benign though but we need to
clean this up for sure.

> 
> Warnings are:
> 
> [   50.702541] OOM killer enabled.
> [   50.702545] Restarting tasks: Starting
> [   50.703553] Restarting tasks: Done
> [   50.704233] efivarfs: resyncing variable state
> [   50.710323] efivarfs: finished resyncing variable state
> [   50.710349] random: crng reseeded on system resumption
> [   50.724547] PM: suspend exit
> [   50.743157] nvme nvme0: 8/0/0 default/read/poll queues
> [   54.814961] PM: suspend entry (s2idle)
> [   55.064704] Filesystems sync: 0.249 seconds
> [   55.112462] Freezing user space processes
> [   55.112647] ------------[ cut here ]------------
> 
> [   55.113009] ======================================================
> [   55.113010] WARNING: possible circular locking dependency detected
> [   55.113011] 6.18.0-rc6-00040-g8b690556d8fe-dirty #168 Not tainted
> [   55.113012] ------------------------------------------------------
> [   55.113012] systemd-sleep/2563 is trying to acquire lock:
> [   55.113013] ffffffff99e7aa00 (console_owner){....}-{0:0}, at: console_lock_spinning_enable+0x3c/0x60
> [   55.113021] 
>                but task is already holding lock:
> [   55.113022] ffff9c3961c65728 (&p->pi_lock){-.-.}-{2:2}, at: task_call_func+0x49/0xf0
> [   55.113025] 
>                which lock already depends on the new lock.
> 
> [   55.113025] 
>                the existing dependency chain (in reverse order) is:
> [   55.113025] 
>                -> #2 (&p->pi_lock){-.-.}-{2:2}:
> [   55.113027]        _raw_spin_lock_irqsave+0x47/0x60
> [   55.113030]        try_to_wake_up+0x69/0xac0
> [   55.113031]        create_worker+0x17c/0x200
> [   55.113033]        workqueue_init+0x27e/0x2e0
> [   55.113036]        kernel_init_freeable+0x15e/0x310
> [   55.113038]        kernel_init+0x16/0x120
> [   55.113039]        ret_from_fork+0x2a9/0x310
> [   55.113041]        ret_from_fork_asm+0x11/0x20
> [   55.113043] 
>                -> #1 (&pool->lock){-.-.}-{2:2}:
> [   55.113045]        _raw_spin_lock+0x2f/0x40
> [   55.113046]        __queue_work+0x23d/0x680
> [   55.113048]        queue_work_on+0x56/0xa0
> [   55.113050]        soft_cursor+0x196/0x240
> [   55.113053]        bit_cursor+0x368/0x5e0
> [   55.113055]        hide_cursor+0x21/0xa0
> [   55.113056]        vt_console_print+0x460/0x480
> [   55.113057]        console_flush_all+0x2de/0x4e0
> [   55.113059]        console_unlock+0x78/0x130
> [   55.113060]        vprintk_emit+0x34c/0x400
> [   55.113062]        _printk+0x67/0x80
> [   55.113064]        int_to_scsilun+0xa/0x30 [scsi_common]
> [   55.113068]        do_one_initcall+0x68/0x390
> [   55.113069]        do_init_module+0x60/0x220
> [   55.113070]        init_module_from_file+0x85/0xc0
> [   55.113071]        idempotent_init_module+0x11a/0x310
> [   55.113072]        __x64_sys_finit_module+0x69/0xd0
> [   55.113073]        do_syscall_64+0x95/0x6e0
> [   55.113076]        entry_SYSCALL_64_after_hwframe+0x4b/0x53
> [   55.113077] 
>                -> #0 (console_owner){....}-{0:0}:
> [   55.113078]        __lock_acquire+0x1444/0x2200
> [   55.113080]        lock_acquire+0xd1/0x2e0
> [   55.113081]        console_lock_spinning_enable+0x58/0x60
> [   55.113083]        console_flush_all+0x2a6/0x4e0
> [   55.113085]        console_unlock+0x78/0x130
> [   55.113086]        vprintk_emit+0x34c/0x400
> [   55.113088]        _printk+0x67/0x80
> [   55.113090]        report_bug.cold+0x13/0x5a
> [   55.113092]        handle_bug+0x18d/0x250
> [   55.113094]        exc_invalid_op+0x13/0x60
> [   55.113096]        asm_exc_invalid_op+0x16/0x20
> [   55.113097]        __set_task_frozen+0x6a/0x90
> [   55.113099]        task_call_func+0x76/0xf0
> [   55.113099]        freeze_task+0x87/0xf0
> [   55.113101]        try_to_freeze_tasks+0xe1/0x2b0
> [   55.113102]        freeze_processes+0x46/0xb0
> [   55.113104]        pm_suspend.cold+0x194/0x29f
> [   55.113106]        state_store+0x68/0xc0
> [   55.113108]        kernfs_fop_write_iter+0x172/0x240
> [   55.113110]        vfs_write+0x249/0x560
> [   55.113112]        ksys_write+0x6d/0xe0
> [   55.113114]        do_syscall_64+0x95/0x6e0
> [   55.113115]        entry_SYSCALL_64_after_hwframe+0x4b/0x53
> [   55.113116] 
>                other info that might help us debug this:
> 
> [   55.113117] Chain exists of:
>                  console_owner --> &pool->lock --> &p->pi_lock
> 
> [   55.113118]  Possible unsafe locking scenario:
> 
> [   55.113119]        CPU0                    CPU1
> [   55.113119]        ----                    ----
> [   55.113119]   lock(&p->pi_lock);
> [   55.113120]                                lock(&pool->lock);
> [   55.113121]                                lock(&p->pi_lock);
> [   55.113121]   lock(console_owner);
> [   55.113122] 
>                 *** DEADLOCK ***
> 
> [   55.113122] 9 locks held by systemd-sleep/2563:
> [   55.113124]  #0: ffff9c39429a2420 (sb_writers#5){.+.+}-{0:0}, at: ksys_write+0x6d/0xe0
> [   55.113127]  #1: ffff9c394683f488 (&of->mutex){+.+.}-{4:4}, at: kernfs_fop_write_iter+0x117/0x240
> [   55.113130]  #2: ffff9c3941257298 (kn->active#212){.+.+}-{0:0}, at: kernfs_fop_write_iter+0x12c/0x240
> [   55.113132]  #3: ffffffff99e6f088 (system_transition_mutex){+.+.}-{4:4}, at: pm_suspend.cold+0x4c/0x29f
> [   55.113136]  #4: ffffffff99e08098 (tasklist_lock){.+.+}-{3:3}, at: try_to_freeze_tasks+0x8a/0x2b0
> [   55.113138]  #5: ffffffff99fa8e98 (freezer_lock){....}-{3:3}, at: freeze_task+0x29/0xf0
> [   55.113141]  #6: ffff9c3961c65728 (&p->pi_lock){-.-.}-{2:2}, at: task_call_func+0x49/0xf0
> [   55.113143]  #7: ffffffff99eeadc0 (console_lock){+.+.}-{0:0}, at: _printk+0x67/0x80
> [   55.113146]  #8: ffffffff99eeae10 (console_srcu){....}-{0:0}, at: console_flush_all+0x3d/0x4e0
> [   55.113149] 
>                stack backtrace:
> [   55.113151] CPU: 8 UID: 0 PID: 2563 Comm: systemd-sleep Not tainted 6.18.0-rc6-00040-g8b690556d8fe-dirty #168 PREEMPT(voluntary) 
> [   55.113153] Hardware name: HP HP Pavilion Aero Laptop 13-be0xxx/8916, BIOS F.17 12/18/2024
> [   55.113154] Call Trace:
> [   55.113155]  <TASK>
> [   55.113156]  dump_stack_lvl+0x6a/0x90
> [   55.113159]  print_circular_bug.cold+0x178/0x1be
> [   55.113162]  check_noncircular+0x142/0x160
> [   55.113166]  __lock_acquire+0x1444/0x2200
> [   55.113169]  lock_acquire+0xd1/0x2e0
> [   55.113170]  ? console_lock_spinning_enable+0x3c/0x60
> [   55.113173]  ? console_lock_spinning_enable+0x35/0x60
> [   55.113175]  ? lock_release+0x17d/0x2c0
> [   55.113177]  console_lock_spinning_enable+0x58/0x60
> [   55.113179]  ? console_lock_spinning_enable+0x3c/0x60
> [   55.113181]  console_flush_all+0x2a6/0x4e0
> [   55.113183]  ? console_flush_all+0x3d/0x4e0
> [   55.113186]  console_unlock+0x78/0x130
> [   55.113188]  vprintk_emit+0x34c/0x400
> [   55.113191]  ? __set_task_frozen+0x6a/0x90
> [   55.113193]  _printk+0x67/0x80
> [   55.113195]  ? lock_is_held_type+0xd5/0x130
> [   55.113199]  report_bug.cold+0x13/0x5a
> [   55.113201]  ? __set_task_frozen+0x6a/0x90
> [   55.113203]  handle_bug+0x18d/0x250
> [   55.113205]  exc_invalid_op+0x13/0x60
> [   55.113207]  asm_exc_invalid_op+0x16/0x20
> [   55.113209] RIP: 0010:__set_task_frozen+0x6a/0x90
> [   55.113211] Code: f7 c5 00 20 00 00 74 06 40 f6 c5 03 74 33 81 e5 00 40 00 00 75 16 8b 15 d8 8c 52 01 85 d2 74 0c 8b 83 f0 0e 00 00 85 c0 74 02 <0f> 0b 8b 43 18 c7 43 18 00 80 00 00 89 43 1c b8 00 80 00 00 5b 5d
> [   55.113212] RSP: 0018:ffffbfba462ef8d0 EFLAGS: 00010002
> [   55.113214] RAX: 0000000000000002 RBX: ffff9c3961c64900 RCX: 0000000000000000
> [   55.113215] RDX: 0000000000000001 RSI: 0000000000000000 RDI: ffff9c3961c64900
> [   55.113216] RBP: 0000000000000000 R08: 00000000000000b6 R09: 0000000000000006
> [   55.113217] R10: 00000000000000f0 R11: 0000000000000006 R12: ffffffff98bd9000
> [   55.113217] R13: 0000000000000000 R14: ffff9c3961c65710 R15: ffff9c3961c65200
> [   55.113218]  ? freezing_slow_path+0x70/0x70
> [   55.113222]  task_call_func+0x76/0xf0
> [   55.113224]  freeze_task+0x87/0xf0
> [   55.113226]  try_to_freeze_tasks+0xe1/0x2b0
> [   55.113229]  ? lockdep_hardirqs_on+0x78/0x100
> [   55.113231]  freeze_processes+0x46/0xb0
> [   55.113233]  pm_suspend.cold+0x194/0x29f
> [   55.113235]  state_store+0x68/0xc0
> [   55.113238]  kernfs_fop_write_iter+0x172/0x240
> [   55.113239]  vfs_write+0x249/0x560
> [   55.113243]  ksys_write+0x6d/0xe0
> [   55.113246]  do_syscall_64+0x95/0x6e0
> [   55.113249]  ? __lock_acquire+0x469/0x2200
> [   55.113252]  ? __lock_acquire+0x469/0x2200
> [   55.113255]  ? lock_acquire+0xd1/0x2e0
> [   55.113257]  ? find_held_lock+0x2b/0x80
> [   55.113258]  ? __folio_batch_add_and_move+0x185/0x320
> [   55.113260]  ? find_held_lock+0x2b/0x80
> [   55.113261]  ? rcu_read_unlock+0x17/0x60
> [   55.113264]  ? rcu_read_unlock+0x17/0x60
> [   55.113266]  ? lock_release+0x17d/0x2c0
> [   55.113269]  ? __lock_acquire+0x469/0x2200
> [   55.113271]  ? __handle_mm_fault+0xac2/0xf10
> [   55.113273]  ? find_held_lock+0x2b/0x80
> [   55.113275]  ? rcu_read_unlock+0x17/0x60
> [   55.113276]  ? rcu_read_unlock+0x17/0x60
> [   55.113278]  ? lock_release+0x17d/0x2c0
> [   55.113279]  ? rcu_is_watching+0xd/0x40
> [   55.113281]  ? find_held_lock+0x2b/0x80
> [   55.113282]  ? exc_page_fault+0x8f/0x260
> [   55.113284]  ? exc_page_fault+0x8f/0x260
> [   55.113285]  ? lock_release+0x17d/0x2c0
> [   55.113287]  ? exc_page_fault+0x132/0x260
> [   55.113289]  entry_SYSCALL_64_after_hwframe+0x4b/0x53
> [   55.113291] RIP: 0033:0x7fd302d0e0d0
> [   55.113292] Code: 2d 0e 00 64 c7 00 16 00 00 00 b8 ff ff ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 80 3d 99 af 0e 00 00 74 17 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 48 83 ec 28 48 89
> [   55.113293] RSP: 002b:00007fffb5edd3d8 EFLAGS: 00000202 ORIG_RAX: 0000000000000001
> [   55.113295] RAX: ffffffffffffffda RBX: 0000000000000004 RCX: 00007fd302d0e0d0
> [   55.113295] RDX: 0000000000000004 RSI: 000055aa9fd98750 RDI: 0000000000000007
> [   55.113296] RBP: 000055aa9fd98750 R08: 00007fd302df1ac0 R09: 0000000000000001
> [   55.113297] R10: 00007fd302df1bb0 R11: 0000000000000202 R12: 0000000000000004
> [   55.113297] R13: 000055aa9fd8f2a0 R14: 00007fd302defea0 R15: 00000000fffffff7
> [   55.113301]  </TASK>
> [   55.113362] WARNING: CPU: 8 PID: 2563 at kernel/freezer.c:140 __set_task_frozen+0x6a/0x90
> [   55.113366] Modules linked in: snd_seq_dummy snd_hrtimer snd_seq snd_seq_device xt_conntrack nft_chain_nat xt_MASQUERADE nf_nat nf_conntrack_netlink nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 xfrm_user xfrm_algo xt_addrtype nft_compat x_tables nf_tables br_netfilter bridge stp llc ccm overlay qrtr rfcomm cmac algif_hash algif_skcipher af_alg bnep binfmt_misc nls_ascii nls_cp437 vfat fat iwlmvm snd_hda_codec_generic intel_rapl_msr uvcvideo snd_hda_codec_hdmi amd_atl mac80211 btusb videobuf2_vmalloc intel_rapl_common btrtl videobuf2_memops snd_hda_intel snd_acp3x_pdm_dma snd_soc_dmic snd_acp3x_rn uvc btintel kvm_amd snd_hda_codec videobuf2_v4l2 snd_soc_core btbcm libarc4 videodev snd_compress btmtk snd_intel_dspcfg ucsi_acpi kvm snd_hwdep videobuf2_common snd_pci_acp6x typec_ucsi bluetooth snd_hda_core snd_pci_acp5x mc ee1004 sg iwlwifi irqbypass roles snd_pcm ecdh_generic snd_rn_pci_acp3x typec wmi_bmof ecc rapl snd_timer snd_acp_config cfg80211 snd snd_soc_acpi sp5100_tco pcspkr k10temp thunderbolt watchdog ccp
> [   55.113424]  snd_pci_acp3x soundcore rfkill ac battery joydev acpi_tad amd_pmc evdev serio_raw msr dm_mod parport_pc ppdev lp parport nvme_fabrics fuse efi_pstore configfs nfnetlink efivarfs autofs4 crc32c_cryptoapi sd_mod uas usb_storage scsi_mod scsi_common btrfs blake2b_generic xor raid6_pq amdgpu drm_client_lib i2c_algo_bit drm_ttm_helper ttm drm_exec drm_suballoc_helper drm_buddy drm_panel_backlight_quirks gpu_sched amdxcp drm_display_helper xhci_pci hid_multitouch drm_kms_helper hid_generic xhci_hcd cec i2c_hid_acpi amd_sfh i2c_hid rc_core nvme usbcore i2c_piix4 video ghash_clmulni_intel hid crc16 usb_common nvme_core i2c_smbus fan button wmi drm aesni_intel
> [   55.113467] CPU: 8 UID: 0 PID: 2563 Comm: systemd-sleep Not tainted 6.18.0-rc6-00040-g8b690556d8fe-dirty #168 PREEMPT(voluntary) 
> [   55.113470] Hardware name: HP HP Pavilion Aero Laptop 13-be0xxx/8916, BIOS F.17 12/18/2024
> [   55.113471] RIP: 0010:__set_task_frozen+0x6a/0x90
> [   55.113473] Code: f7 c5 00 20 00 00 74 06 40 f6 c5 03 74 33 81 e5 00 40 00 00 75 16 8b 15 d8 8c 52 01 85 d2 74 0c 8b 83 f0 0e 00 00 85 c0 74 02 <0f> 0b 8b 43 18 c7 43 18 00 80 00 00 89 43 1c b8 00 80 00 00 5b 5d
> [   55.113474] RSP: 0018:ffffbfba462ef8d0 EFLAGS: 00010002
> [   55.113476] RAX: 0000000000000002 RBX: ffff9c3961c64900 RCX: 0000000000000000
> [   55.113477] RDX: 0000000000000001 RSI: 0000000000000000 RDI: ffff9c3961c64900
> [   55.113479] RBP: 0000000000000000 R08: 00000000000000b6 R09: 0000000000000006
> [   55.113480] R10: 00000000000000f0 R11: 0000000000000006 R12: ffffffff98bd9000
> [   55.113481] R13: 0000000000000000 R14: ffff9c3961c65710 R15: ffff9c3961c65200
> [   55.113482] FS:  00007fd303258980(0000) GS:ffff9c3cb2d98000(0000) knlGS:0000000000000000
> [   55.113484] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [   55.113485] CR2: 0000561c6a183168 CR3: 0000000122bcb000 CR4: 0000000000750ef0
> [   55.113487] PKRU: 55555554
> [   55.113488] Call Trace:
> [   55.113489]  <TASK>
> [   55.113491]  task_call_func+0x76/0xf0
> [   55.113493]  freeze_task+0x87/0xf0
> [   55.113496]  try_to_freeze_tasks+0xe1/0x2b0
> [   55.113499]  ? lockdep_hardirqs_on+0x78/0x100
> [   55.113502]  freeze_processes+0x46/0xb0
> [   55.113505]  pm_suspend.cold+0x194/0x29f
> [   55.113507]  state_store+0x68/0xc0
> [   55.113510]  kernfs_fop_write_iter+0x172/0x240
> [   55.113513]  vfs_write+0x249/0x560
> [   55.113518]  ksys_write+0x6d/0xe0
> [   55.113521]  do_syscall_64+0x95/0x6e0
> [   55.113524]  ? __lock_acquire+0x469/0x2200
> [   55.113528]  ? __lock_acquire+0x469/0x2200
> [   55.113532]  ? lock_acquire+0xd1/0x2e0
> [   55.113534]  ? find_held_lock+0x2b/0x80
> [   55.113536]  ? __folio_batch_add_and_move+0x185/0x320
> [   55.113538]  ? find_held_lock+0x2b/0x80
> [   55.113540]  ? rcu_read_unlock+0x17/0x60
> [   55.113543]  ? rcu_read_unlock+0x17/0x60
> [   55.113545]  ? lock_release+0x17d/0x2c0
> [   55.113549]  ? __lock_acquire+0x469/0x2200
> [   55.113551]  ? __handle_mm_fault+0xac2/0xf10
> [   55.113554]  ? find_held_lock+0x2b/0x80
> [   55.113556]  ? rcu_read_unlock+0x17/0x60
> [   55.113558]  ? rcu_read_unlock+0x17/0x60
> [   55.113561]  ? lock_release+0x17d/0x2c0
> [   55.113563]  ? rcu_is_watching+0xd/0x40
> [   55.113565]  ? find_held_lock+0x2b/0x80
> [   55.113566]  ? exc_page_fault+0x8f/0x260
> [   55.113568]  ? exc_page_fault+0x8f/0x260
> [   55.113570]  ? lock_release+0x17d/0x2c0
> [   55.113573]  ? exc_page_fault+0x132/0x260
> [   55.113576]  entry_SYSCALL_64_after_hwframe+0x4b/0x53
> [   55.113578] RIP: 0033:0x7fd302d0e0d0
> [   55.113579] Code: 2d 0e 00 64 c7 00 16 00 00 00 b8 ff ff ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 80 3d 99 af 0e 00 00 74 17 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 48 83 ec 28 48 89
> [   55.113581] RSP: 002b:00007fffb5edd3d8 EFLAGS: 00000202 ORIG_RAX: 0000000000000001
> [   55.113583] RAX: ffffffffffffffda RBX: 0000000000000004 RCX: 00007fd302d0e0d0
> [   55.113584] RDX: 0000000000000004 RSI: 000055aa9fd98750 RDI: 0000000000000007
> [   55.113585] RBP: 000055aa9fd98750 R08: 00007fd302df1ac0 R09: 0000000000000001
> [   55.113586] R10: 00007fd302df1bb0 R11: 0000000000000202 R12: 0000000000000004
> [   55.113587] R13: 000055aa9fd8f2a0 R14: 00007fd302defea0 R15: 00000000fffffff7
> [   55.113591]  </TASK>
> [   55.113592] irq event stamp: 22480
> [   55.113594] hardirqs last  enabled at (22479): [<ffffffff997159b8>] _raw_spin_unlock_irqrestore+0x48/0x60
> [   55.113596] hardirqs last disabled at (22480): [<ffffffff9971575b>] _raw_spin_lock_irqsave+0x5b/0x60
> [   55.113598] softirqs last  enabled at (21756): [<ffffffff98a91401>] kernel_fpu_end+0x31/0x40
> [   55.113600] softirqs last disabled at (21754): [<ffffffff98a91a66>] kernel_fpu_begin_mask+0xd6/0x150
> [   55.113602] ---[ end trace 0000000000000000 ]---
> [   55.115030] Freezing user space processes completed (elapsed 0.002 seconds)
> [   55.115035] OOM killer disabled.
> [   55.115037] Freezing remaining freezable tasks
> [   55.116230] Freezing remaining freezable tasks completed (elapsed 0.001 seconds)
> [   55.116233] printk: Suspending console(s) (use no_console_suspend to debug)
> 
> And another:
> 
> [   90.334155] OOM killer enabled.
> [   90.334159] Restarting tasks: Starting
> [   90.335256] Restarting tasks: Done
> [   90.336242] efivarfs: resyncing variable state
> [   90.347855] efivarfs: finished resyncing variable state
> [   90.351615] random: crng reseeded on system resumption
> [   90.402289] Bluetooth: MGMT ver 1.23
> [   90.418337] PM: suspend exit
> [   90.418508] PM: suspend entry (s2idle)
> [   90.442310] Filesystems sync: 0.023 seconds
> [   90.464970] Freezing user space processes
> [   90.465209] ------------[ cut here ]------------
> [   90.465655] WARNING: CPU: 12 PID: 3770 at kernel/freezer.c:140 __set_task_frozen+0x6a/0x90
> [   90.465662] Modules linked in: snd_seq_dummy snd_hrtimer snd_seq snd_seq_device xt_conntrack nft_chain_nat xt_MASQUERADE nf_nat nf_conntrack_netlink nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 xfrm_user xfrm_algo xt_addrtype nft_compat x_tables nf_tables br_netfilter bridge stp llc ccm overlay qrtr rfcomm cmac algif_hash algif_skcipher af_alg bnep binfmt_misc ext4 mbcache jbd2 nls_ascii nls_cp437 vfat fat iwlmvm intel_rapl_msr amd_atl intel_rapl_common snd_hda_codec_generic snd_hda_codec_hdmi btusb uvcvideo mac80211 btrtl videobuf2_vmalloc btintel kvm_amd videobuf2_memops snd_hda_intel btbcm uvc libarc4 snd_hda_codec btmtk videobuf2_v4l2 kvm snd_intel_dspcfg snd_hda_scodec_cs35l41_i2c snd_hwdep bluetooth videodev snd_hda_scodec_cs35l41 snd_hda_core irqbypass iwlwifi ideapad_laptop snd_soc_cs_amp_lib videobuf2_common ecdh_generic sparse_keymap snd_pcm cs_dsp rapl ecc mc wmi_bmof ee1004 platform_profile pcspkr cfg80211 snd_soc_cs35l41_lib snd_timer k10temp ccp sg rfkill battery snd soundcore cm32181
> [   90.466192]  serial_multi_instantiate industrialio joydev ac evdev msr parport_pc ppdev lp parport nvme_fabrics fuse efi_pstore configfs nfnetlink efivarfs autofs4 crc32c_cryptoapi btrfs blake2b_generic xor raid6_pq dm_crypt sd_mod uas usbhid usb_storage amdgpu drm_client_lib i2c_algo_bit drm_ttm_helper ttm drm_exec drm_suballoc_helper drm_buddy drm_panel_backlight_quirks dm_mod gpu_sched ahci amdxcp r8169 libahci drm_display_helper ucsi_acpi realtek libata drm_kms_helper typec_ucsi hid_multitouch xhci_pci mdio_devres roles cec sp5100_tco hid_generic xhci_hcd libphy scsi_mod nvme video typec rc_core wdat_wdt i2c_piix4 ghash_clmulni_intel nvme_core mdio_bus serio_raw watchdog scsi_common usbcore thunderbolt crc16 i2c_hid_acpi i2c_smbus usb_common i2c_hid wmi hid drm button aesni_intel
> [   90.466268] CPU: 12 UID: 0 PID: 3770 Comm: systemd-sleep Not tainted 6.18.0-rc6-00040-g8b690556d8fe-dirty #168 PREEMPT(voluntary) 
> [   90.466272] Hardware name: LENOVO 82N6/LNVNB161216, BIOS GKCN65WW 01/16/2024
> [   90.466274] RIP: 0010:__set_task_frozen+0x6a/0x90
> [   90.466277] Code: f7 c5 00 20 00 00 74 06 40 f6 c5 03 74 33 81 e5 00 40 00 00 75 16 8b 15 d8 8c 52 01 85 d2 74 0c 8b 83 f0 0e 00 00 85 c0 74 02 <0f> 0b 8b 43 18 c7 43 18 00 80 00 00 89 43 1c b8 00 80 00 00 5b 5d
> [   90.466279] RSP: 0018:ffffaa8f8bf5bab0 EFLAGS: 00010002
> [   90.466282] RAX: 0000000000000002 RBX: ffff8bd9e5d12480 RCX: 0000000000000000
> [   90.466284] RDX: 0000000000000001 RSI: 0000000000000000 RDI: ffff8bd9e5d12480
> [   90.466285] RBP: 0000000000000000 R08: 00000000000000b4 R09: 0000000000000006
> [   90.466287] R10: 00000000000000f0 R11: 0000000000000006 R12: ffffffff83dd9000
> [   90.466288] R13: 0000000000000000 R14: ffff8bd9e5d13290 R15: ffff8bd9e5d12d80
> [   90.466290] FS:  00007f5e1fc45980(0000) GS:ffff8bdfc4698000(0000) knlGS:0000000000000000
> [   90.466292] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [   90.466293] CR2: 00007f5e2043b488 CR3: 000000016063e000 CR4: 0000000000750ef0
> [   90.466295] PKRU: 55555554
> [   90.466296] Call Trace:
> [   90.466298]  <TASK>
> [   90.466301]  task_call_func+0x76/0xf0
> [   90.466307]  freeze_task+0x87/0xf0
> [   90.466312]  try_to_freeze_tasks+0xe1/0x2b0
> [   90.466317]  ? lockdep_hardirqs_on+0x78/0x100
> [   90.466322]  freeze_processes+0x46/0xb0
> [   90.466326]  pm_suspend.cold+0x194/0x29f
> [   90.466330]  state_store+0x68/0xc0
> [   90.466335]  kernfs_fop_write_iter+0x172/0x240
> [   90.466340]  vfs_write+0x249/0x560
> [   90.466350]  ksys_write+0x6d/0xe0
> [   90.466355]  do_syscall_64+0x95/0x6e0
> [   90.466363]  ? entry_SYSCALL_64_after_hwframe+0x4b/0x53
> [   90.466366]  ? lockdep_hardirqs_on+0x78/0x100
> [   90.466369]  ? do_syscall_64+0x1ad/0x6e0
> [   90.466372]  ? find_held_lock+0x2b/0x80
> [   90.466376]  ? do_sys_openat2+0xa4/0xe0
> [   90.466379]  ? kmem_cache_free+0x13e/0x640
> [   90.466385]  ? do_sys_openat2+0xa4/0xe0
> [   90.466387]  ? do_sys_openat2+0xa4/0xe0
> [   90.466390]  ? find_held_lock+0x2b/0x80
> [   90.466395]  ? entry_SYSCALL_64_after_hwframe+0x4b/0x53
> [   90.466397]  ? lockdep_hardirqs_on+0x78/0x100
> [   90.466400]  ? do_syscall_64+0x1ad/0x6e0
> [   90.466402]  ? exc_page_fault+0x132/0x260
> [   90.466409]  entry_SYSCALL_64_after_hwframe+0x4b/0x53
> [   90.466410] RIP: 0033:0x7f5e1fe99687
> [   90.466414] Code: 48 89 fa 4c 89 df e8 58 b3 00 00 8b 93 08 03 00 00 59 5e 48 83 f8 fc 74 1a 5b c3 0f 1f 84 00 00 00 00 00 48 8b 44 24 10 0f 05 <5b> c3 0f 1f 80 00 00 00 00 83 e2 39 83 fa 08 75 de e8 23 ff ff ff
> [   90.466415] RSP: 002b:00007fff3d312840 EFLAGS: 00000202 ORIG_RAX: 0000000000000001
> [   90.466418] RAX: ffffffffffffffda RBX: 00007f5e1fc45980 RCX: 00007f5e1fe99687
> [   90.466419] RDX: 0000000000000007 RSI: 000055c3cbfbce50 RDI: 0000000000000007
> [   90.466421] RBP: 000055c3cbfbce50 R08: 0000000000000000 R09: 0000000000000000
> [   90.466422] R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000007
> [   90.466423] R13: 000055c3cbfb22a0 R14: 00007f5e1ffefe80 R15: 00000000fffffff7
> [   90.466435]  </TASK>
> [   90.466437] irq event stamp: 118990
> [   90.466438] hardirqs last  enabled at (118989): [<ffffffff849159b8>] _raw_spin_unlock_irqrestore+0x48/0x60
> [   90.466441] hardirqs last disabled at (118990): [<ffffffff8491575b>] _raw_spin_lock_irqsave+0x5b/0x60
> [   90.466443] softirqs last  enabled at (118630): [<ffffffff83cf99ed>] __irq_exit_rcu+0xcd/0x140
> [   90.466446] softirqs last disabled at (118623): [<ffffffff83cf99ed>] __irq_exit_rcu+0xcd/0x140
> [   90.466448] ---[ end trace 0000000000000000 ]---
> [   90.466528] ------------[ cut here ]------------
> [   90.466530] WARNING: CPU: 12 PID: 3770 at kernel/freezer.c:140 __set_task_frozen+0x6a/0x90
> [   90.466535] Modules linked in: snd_seq_dummy snd_hrtimer snd_seq snd_seq_device xt_conntrack nft_chain_nat xt_MASQUERADE nf_nat nf_conntrack_netlink nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 xfrm_user xfrm_algo xt_addrtype nft_compat x_tables nf_tables br_netfilter bridge stp llc ccm overlay qrtr rfcomm cmac algif_hash algif_skcipher af_alg bnep binfmt_misc ext4 mbcache jbd2 nls_ascii nls_cp437 vfat fat iwlmvm intel_rapl_msr amd_atl intel_rapl_common snd_hda_codec_generic snd_hda_codec_hdmi btusb uvcvideo mac80211 btrtl videobuf2_vmalloc btintel kvm_amd videobuf2_memops snd_hda_intel btbcm uvc libarc4 snd_hda_codec btmtk videobuf2_v4l2 kvm snd_intel_dspcfg snd_hda_scodec_cs35l41_i2c snd_hwdep bluetooth videodev snd_hda_scodec_cs35l41 snd_hda_core irqbypass iwlwifi ideapad_laptop snd_soc_cs_amp_lib videobuf2_common ecdh_generic sparse_keymap snd_pcm cs_dsp rapl ecc mc wmi_bmof ee1004 platform_profile pcspkr cfg80211 snd_soc_cs35l41_lib snd_timer k10temp ccp sg rfkill battery snd soundcore cm32181
> [   90.466665]  serial_multi_instantiate industrialio joydev ac evdev msr parport_pc ppdev lp parport nvme_fabrics fuse efi_pstore configfs nfnetlink efivarfs autofs4 crc32c_cryptoapi btrfs blake2b_generic xor raid6_pq dm_crypt sd_mod uas usbhid usb_storage amdgpu drm_client_lib i2c_algo_bit drm_ttm_helper ttm drm_exec drm_suballoc_helper drm_buddy drm_panel_backlight_quirks dm_mod gpu_sched ahci amdxcp r8169 libahci drm_display_helper ucsi_acpi realtek libata drm_kms_helper typec_ucsi hid_multitouch xhci_pci mdio_devres roles cec sp5100_tco hid_generic xhci_hcd libphy scsi_mod nvme video typec rc_core wdat_wdt i2c_piix4 ghash_clmulni_intel nvme_core mdio_bus serio_raw watchdog scsi_common usbcore thunderbolt crc16 i2c_hid_acpi i2c_smbus usb_common i2c_hid wmi hid drm button aesni_intel
> [   90.466759] CPU: 12 UID: 0 PID: 3770 Comm: systemd-sleep Tainted: G        W           6.18.0-rc6-00040-g8b690556d8fe-dirty #168 PREEMPT(voluntary) 
> [   90.466763] Tainted: [W]=WARN
> [   90.466765] Hardware name: LENOVO 82N6/LNVNB161216, BIOS GKCN65WW 01/16/2024
> [   90.466767] RIP: 0010:__set_task_frozen+0x6a/0x90
> [   90.466770] Code: f7 c5 00 20 00 00 74 06 40 f6 c5 03 74 33 81 e5 00 40 00 00 75 16 8b 15 d8 8c 52 01 85 d2 74 0c 8b 83 f0 0e 00 00 85 c0 74 02 <0f> 0b 8b 43 18 c7 43 18 00 80 00 00 89 43 1c b8 00 80 00 00 5b 5d
> [   90.466772] RSP: 0018:ffffaa8f8bf5bab0 EFLAGS: 00010002
> [   90.466775] RAX: 0000000000000002 RBX: ffff8bda00862480 RCX: 0000000000000000
> [   90.466777] RDX: 0000000000000001 RSI: 0000000000000000 RDI: ffff8bda00862480
> [   90.466779] RBP: 0000000000000000 R08: 00000000000000b4 R09: 0000000000000006
> [   90.466781] R10: 00000000000000f0 R11: 0000000000000006 R12: ffffffff83dd9000
> [   90.466783] R13: 0000000000000000 R14: ffff8bda00863290 R15: ffff8bd9e5d45200
> [   90.466785] FS:  00007f5e1fc45980(0000) GS:ffff8bdfc4698000(0000) knlGS:0000000000000000
> [   90.466787] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [   90.466789] CR2: 00007f5e2043b488 CR3: 000000016063e000 CR4: 0000000000750ef0
> [   90.466791] PKRU: 55555554
> [   90.466793] Call Trace:
> [   90.466794]  <TASK>
> [   90.466797]  task_call_func+0x76/0xf0
> [   90.466805]  freeze_task+0x87/0xf0
> [   90.466812]  try_to_freeze_tasks+0xe1/0x2b0
> [   90.466817]  ? lockdep_hardirqs_on+0x78/0x100
> [   90.466824]  freeze_processes+0x46/0xb0
> [   90.466828]  pm_suspend.cold+0x194/0x29f
> [   90.466833]  state_store+0x68/0xc0
> [   90.466840]  kernfs_fop_write_iter+0x172/0x240
> [   90.466846]  vfs_write+0x249/0x560
> [   90.466859]  ksys_write+0x6d/0xe0
> [   90.466866]  do_syscall_64+0x95/0x6e0
> [   90.466877]  ? entry_SYSCALL_64_after_hwframe+0x4b/0x53
> [   90.466880]  ? lockdep_hardirqs_on+0x78/0x100
> [   90.466883]  ? do_syscall_64+0x1ad/0x6e0
> [   90.466888]  ? find_held_lock+0x2b/0x80
> [   90.466894]  ? do_sys_openat2+0xa4/0xe0
> [   90.466896]  ? kmem_cache_free+0x13e/0x640
> [   90.466905]  ? do_sys_openat2+0xa4/0xe0
> [   90.466908]  ? do_sys_openat2+0xa4/0xe0
> [   90.466911]  ? find_held_lock+0x2b/0x80
> [   90.466918]  ? entry_SYSCALL_64_after_hwframe+0x4b/0x53
> [   90.466921]  ? lockdep_hardirqs_on+0x78/0x100
> [   90.466925]  ? do_syscall_64+0x1ad/0x6e0
> [   90.466929]  ? exc_page_fault+0x132/0x260
> [   90.466938]  entry_SYSCALL_64_after_hwframe+0x4b/0x53
> [   90.466940] RIP: 0033:0x7f5e1fe99687
> [   90.466943] Code: 48 89 fa 4c 89 df e8 58 b3 00 00 8b 93 08 03 00 00 59 5e 48 83 f8 fc 74 1a 5b c3 0f 1f 84 00 00 00 00 00 48 8b 44 24 10 0f 05 <5b> c3 0f 1f 80 00 00 00 00 83 e2 39 83 fa 08 75 de e8 23 ff ff ff
> [   90.466945] RSP: 002b:00007fff3d312840 EFLAGS: 00000202 ORIG_RAX: 0000000000000001
> [   90.466949] RAX: ffffffffffffffda RBX: 00007f5e1fc45980 RCX: 00007f5e1fe99687
> [   90.466950] RDX: 0000000000000007 RSI: 000055c3cbfbce50 RDI: 0000000000000007
> [   90.466952] RBP: 000055c3cbfbce50 R08: 0000000000000000 R09: 0000000000000000
> [   90.466954] R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000007
> [   90.466956] R13: 000055c3cbfb22a0 R14: 00007f5e1ffefe80 R15: 00000000fffffff7
> [   90.466971]  </TASK>
> [   90.466973] irq event stamp: 119140
> [   90.466975] hardirqs last  enabled at (119139): [<ffffffff849159b8>] _raw_spin_unlock_irqrestore+0x48/0x60
> [   90.466977] hardirqs last disabled at (119140): [<ffffffff8491575b>] _raw_spin_lock_irqsave+0x5b/0x60
> [   90.466980] softirqs last  enabled at (118630): [<ffffffff83cf99ed>] __irq_exit_rcu+0xcd/0x140
> [   90.466983] softirqs last disabled at (118623): [<ffffffff83cf99ed>] __irq_exit_rcu+0xcd/0x140
> [   90.466987] ---[ end trace 0000000000000000 ]---
> [   90.468818] Freezing user space processes completed (elapsed 0.003 seconds)
> [   90.468822] OOM killer disabled.
> [   90.468824] Freezing remaining freezable tasks
> [   90.470358] Freezing remaining freezable tasks completed (elapsed 0.001 seconds)
> [   90.470361] printk: Suspending console(s) (use no_console_suspend to debug)
> 
> #regzbot title: Intermittent suspend __set_task_frozen lock warnings
> #regzbot introduced: a3f8f8662771285511ae26c4c8d3ba1cd22159b9

^ permalink raw reply

* Re: [PATCH v2 08/10] efi: Support EDID information
From: Thomas Zimmermann @ 2025-11-25  7:19 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: javierm, arnd, richard.lyu, x86, linux-arm-kernel, linux-kernel,
	linux-efi, loongarch, linux-riscv, dri-devel, linux-hyperv,
	linux-pci, linux-fbdev
In-Reply-To: <CAMj1kXFtsneE3dFgUx6Hd=iBhD8YpvjfTSi-KZpuNaXfX07KyA@mail.gmail.com>

Hi

Am 24.11.25 um 18:04 schrieb Ard Biesheuvel:
> On Mon, 24 Nov 2025 at 18:01, Ard Biesheuvel <ardb@kernel.org> wrote:
>> On Mon, 24 Nov 2025 at 17:52, Thomas Zimmermann <tzimmermann@suse.de> wrote:
>>> Add LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID to the list of config-table
>>> UUIDs. Read sysfb_primary_display from the entry. The UUID has been
>>> generated with uuidgen.
>>>
>>> Still support LINUX_EFI_SCREEN_INFO_TABLE_GUID as fallback in case an
>>> older boot loader invokes the kernel.
>>>
>>> If CONFIG_FIRMWARE_EDID=n, EDID information is disabled.
>>>
>>> Make the Kconfig symbol CONFIG_FIRMWARE_EDID available with EFI. Setting
>>> the value to 'n' disables EDID support.
>>>
>>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> Why are we adding a new config table again?
>>
>>
> Note that LINUX_EFI_SCREEN_INFO_TABLE_GUID is internal ABI only
> between the EFI stub and the core kernel.

Ah, ok. That's my misconception. I was thinking that we have to support 
external boot loaders building a config table.

I'll just extend the existing UUID then.

Best regards
Thomas


-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich, (HRB 36809, AG Nürnberg)



^ permalink raw reply

* Re: [PATCH v2] efistub: Only link libstub to final vmlinux
From: Josh Poimboeuf @ 2025-11-25  1:49 UTC (permalink / raw)
  To: Tiezhu Yang
  Cc: Huacai Chen, Will Deacon, Catalin Marinas, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Madhavan T. Venkataraman,
	Ard Biesheuvel, loongarch, linux-arm-kernel, linux-riscv,
	linux-efi, linux-kbuild, linux-kernel, Nathan Chancellor
In-Reply-To: <fc4fa66f-15a0-ebe3-0a27-f3f38b03bbdb@loongson.cn>

On Sun, Nov 23, 2025 at 11:37:14AM +0800, Tiezhu Yang wrote:
> On 11/23/25 10:29, Huacai Chen wrote:
> > Is it possible to improve objtool that can handle indirect __noreturn functions?

Someday that will be possible via a new compiler feature or plugin.  But
today it can't be done.

> > Is it possible to improve objtool that can handle
> > OBJECT_FILES_NON_STANDARD event LTO is enabled?

No, that is purely a makefile construct which should in general be
avoided anyway for a variety of reasons.

> > Is it possible to improve objtool that only ignore __efistub prefix
> > for LoongArch?
> [...]
> static int validate_branch()
> {
> ...
> 			if (arch_is_efistub(func))
> 				return 0;
> 
> 			if (file->ignore_unreachables)
> 				return 0;
> 
> 			WARN("%s() falls through to next function %s()",
> 			     func->name, insn_func(insn)->name);
> 			func->warned = 1;
> 
> 			return 1;
> ...
> }

That only silences the warning, it doesn't prevent objtool from doing
the actual stack validation or ORC generation.  Neither of which makes
sense for libstub.

And objtool has many other features beyond just stack validation and
ORC.  None of those make sense for libstub either.

To fully exclude all libstub code from objtool, these arch_is_efistub()
checks would need to be sprinkled all over the place.

That would be a lot more fragile than just excluding libstub from
vmlinux.o in the first place.

-- 
Josh

^ permalink raw reply

* Re: [PATCH v2 04/10] sysfb: Replace screen_info with sysfb_primary_display
From: Bjorn Helgaas @ 2025-11-24 23:56 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: ardb, javierm, arnd, richard.lyu, x86, linux-arm-kernel,
	linux-kernel, linux-efi, loongarch, linux-riscv, dri-devel,
	linux-hyperv, linux-pci, linux-fbdev
In-Reply-To: <20251124165116.502813-5-tzimmermann@suse.de>

On Mon, Nov 24, 2025 at 05:40:16PM +0100, Thomas Zimmermann wrote:
> Replace the global screen_info with sysfb_primary_display of type
> struct sysfb_display_info. Adapt all users of screen_info.
> 
> Instances of screen_info are defined for x86, loongarch and EFI,
> with only one instance compiled into a specific build. Replace all
> of them with sysfb_primary_display.
> 
> All existing users of screen_info are updated by pointing them to
> sysfb_primary_display.screen instead. This introduces some churn to
> the code, but has no impact on functionality.
> 
> Boot parameters and EFI config tables are unchanged. They transfer
> screen_info as before. The logic in EFI's alloc_screen_info() changes
> slightly, as it now returns the screen field of sysfb_primary_display.
> 
> v2:
> - update comment
> - rename init_screen_info() to init_primary_display()
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Acked-by: Arnd Bergmann <arnd@arndb.de>
> Acked-by: Ard Biesheuvel <ardb@kernel.org>

Acked-by: Bjorn Helgaas <bhelgaas@google.com>  # drivers/pci/

> ---
>  arch/arm64/kernel/image-vars.h                |  2 +-
>  arch/loongarch/kernel/efi.c                   | 15 +++++++------
>  arch/loongarch/kernel/image-vars.h            |  2 +-
>  arch/riscv/kernel/image-vars.h                |  2 +-
>  arch/x86/kernel/kexec-bzimage64.c             |  4 +++-
>  arch/x86/kernel/setup.c                       | 10 +++++----
>  arch/x86/video/video-common.c                 |  4 ++--
>  drivers/firmware/efi/earlycon.c               |  8 +++----
>  drivers/firmware/efi/efi-init.c               | 22 +++++++++----------
>  drivers/firmware/efi/libstub/efi-stub-entry.c | 18 ++++++++++-----
>  drivers/firmware/efi/sysfb_efi.c              |  4 ++--
>  drivers/firmware/sysfb.c                      |  6 ++---
>  drivers/hv/vmbus_drv.c                        |  6 ++---
>  drivers/pci/vgaarb.c                          |  4 ++--
>  drivers/video/screen_info_pci.c               |  5 +++--
>  include/linux/screen_info.h                   |  2 --
>  include/linux/sysfb.h                         |  5 +++--
>  17 files changed, 66 insertions(+), 53 deletions(-)
> 
> diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h
> index 85bc629270bd..d7b0d12b1015 100644
> --- a/arch/arm64/kernel/image-vars.h
> +++ b/arch/arm64/kernel/image-vars.h
> @@ -38,7 +38,7 @@ PROVIDE(__efistub__end			= _end);
>  PROVIDE(__efistub___inittext_end       	= __inittext_end);
>  PROVIDE(__efistub__edata		= _edata);
>  #if defined(CONFIG_EFI_EARLYCON) || defined(CONFIG_SYSFB)
> -PROVIDE(__efistub_screen_info		= screen_info);
> +PROVIDE(__efistub_sysfb_primary_display	= sysfb_primary_display);
>  #endif
>  PROVIDE(__efistub__ctype		= _ctype);
>  
> diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c
> index 860a3bc030e0..638a392d2cd2 100644
> --- a/arch/loongarch/kernel/efi.c
> +++ b/arch/loongarch/kernel/efi.c
> @@ -18,7 +18,7 @@
>  #include <linux/kobject.h>
>  #include <linux/memblock.h>
>  #include <linux/reboot.h>
> -#include <linux/screen_info.h>
> +#include <linux/sysfb.h>
>  #include <linux/uaccess.h>
>  
>  #include <asm/early_ioremap.h>
> @@ -75,11 +75,11 @@ bool efi_poweroff_required(void)
>  unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;
>  
>  #if defined(CONFIG_SYSFB) || defined(CONFIG_EFI_EARLYCON)
> -struct screen_info screen_info __section(".data");
> -EXPORT_SYMBOL_GPL(screen_info);
> +struct sysfb_display_info sysfb_primary_display __section(".data");
> +EXPORT_SYMBOL_GPL(sysfb_primary_display);
>  #endif
>  
> -static void __init init_screen_info(void)
> +static void __init init_primary_display(void)
>  {
>  	struct screen_info *si;
>  
> @@ -91,11 +91,12 @@ static void __init init_screen_info(void)
>  		pr_err("Could not map screen_info config table\n");
>  		return;
>  	}
> -	screen_info = *si;
> +	sysfb_primary_display.screen = *si;
>  	memset(si, 0, sizeof(*si));
>  	early_memunmap(si, sizeof(*si));
>  
> -	memblock_reserve(__screen_info_lfb_base(&screen_info), screen_info.lfb_size);
> +	memblock_reserve(__screen_info_lfb_base(&sysfb_primary_display.screen),
> +			 sysfb_primary_display.screen.lfb_size);
>  }
>  
>  void __init efi_init(void)
> @@ -127,7 +128,7 @@ void __init efi_init(void)
>  	set_bit(EFI_CONFIG_TABLES, &efi.flags);
>  
>  	if (IS_ENABLED(CONFIG_EFI_EARLYCON) || IS_ENABLED(CONFIG_SYSFB))
> -		init_screen_info();
> +		init_primary_display();
>  
>  	if (boot_memmap == EFI_INVALID_TABLE_ADDR)
>  		return;
> diff --git a/arch/loongarch/kernel/image-vars.h b/arch/loongarch/kernel/image-vars.h
> index 41ddcf56d21c..e557ebd46c2b 100644
> --- a/arch/loongarch/kernel/image-vars.h
> +++ b/arch/loongarch/kernel/image-vars.h
> @@ -12,7 +12,7 @@ __efistub_kernel_entry		= kernel_entry;
>  __efistub_kernel_asize		= kernel_asize;
>  __efistub_kernel_fsize		= kernel_fsize;
>  #if defined(CONFIG_EFI_EARLYCON) || defined(CONFIG_SYSFB)
> -__efistub_screen_info		= screen_info;
> +__efistub_sysfb_primary_display	= sysfb_primary_display;
>  #endif
>  
>  #endif
> diff --git a/arch/riscv/kernel/image-vars.h b/arch/riscv/kernel/image-vars.h
> index 3df30dd1c458..3bd9d06a8b8f 100644
> --- a/arch/riscv/kernel/image-vars.h
> +++ b/arch/riscv/kernel/image-vars.h
> @@ -29,7 +29,7 @@ __efistub__end			= _end;
>  __efistub__edata		= _edata;
>  __efistub___init_text_end	= __init_text_end;
>  #if defined(CONFIG_EFI_EARLYCON) || defined(CONFIG_SYSFB)
> -__efistub_screen_info		= screen_info;
> +__efistub_sysfb_primary_display	= sysfb_primary_display;
>  #endif
>  
>  #endif
> diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
> index c3244ac680d1..7508d0ccc740 100644
> --- a/arch/x86/kernel/kexec-bzimage64.c
> +++ b/arch/x86/kernel/kexec-bzimage64.c
> @@ -20,6 +20,7 @@
>  #include <linux/of_fdt.h>
>  #include <linux/efi.h>
>  #include <linux/random.h>
> +#include <linux/sysfb.h>
>  
>  #include <asm/bootparam.h>
>  #include <asm/setup.h>
> @@ -303,7 +304,8 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params,
>  	params->hdr.hardware_subarch = boot_params.hdr.hardware_subarch;
>  
>  	/* Copying screen_info will do? */
> -	memcpy(&params->screen_info, &screen_info, sizeof(struct screen_info));
> +	memcpy(&params->screen_info, &sysfb_primary_display.screen,
> +	       sizeof(sysfb_primary_display.screen));
>  
>  	/* Fill in memsize later */
>  	params->screen_info.ext_mem_k = 0;
> diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
> index 1b2edd07a3e1..675e4b9deb1f 100644
> --- a/arch/x86/kernel/setup.c
> +++ b/arch/x86/kernel/setup.c
> @@ -22,6 +22,7 @@
>  #include <linux/random.h>
>  #include <linux/root_dev.h>
>  #include <linux/static_call.h>
> +#include <linux/sysfb.h>
>  #include <linux/swiotlb.h>
>  #include <linux/tboot.h>
>  #include <linux/usb/xhci-dbgp.h>
> @@ -211,8 +212,9 @@ arch_initcall(init_x86_sysctl);
>  /*
>   * Setup options
>   */
> -struct screen_info screen_info;
> -EXPORT_SYMBOL(screen_info);
> +
> +struct sysfb_display_info sysfb_primary_display;
> +EXPORT_SYMBOL(sysfb_primary_display);
>  #if defined(CONFIG_FIRMWARE_EDID)
>  struct edid_info edid_info;
>  EXPORT_SYMBOL_GPL(edid_info);
> @@ -526,7 +528,7 @@ static void __init parse_setup_data(void)
>  static void __init parse_boot_params(void)
>  {
>  	ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev);
> -	screen_info = boot_params.screen_info;
> +	sysfb_primary_display.screen = boot_params.screen_info;
>  #if defined(CONFIG_FIRMWARE_EDID)
>  	edid_info = boot_params.edid_info;
>  #endif
> @@ -1254,7 +1256,7 @@ void __init setup_arch(char **cmdline_p)
>  #ifdef CONFIG_VT
>  #if defined(CONFIG_VGA_CONSOLE)
>  	if (!efi_enabled(EFI_BOOT) || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
> -		vgacon_register_screen(&screen_info);
> +		vgacon_register_screen(&sysfb_primary_display.screen);
>  #endif
>  #endif
>  	x86_init.oem.banner();
> diff --git a/arch/x86/video/video-common.c b/arch/x86/video/video-common.c
> index e0aeee99bc99..152789f00fcd 100644
> --- a/arch/x86/video/video-common.c
> +++ b/arch/x86/video/video-common.c
> @@ -9,7 +9,7 @@
>  
>  #include <linux/module.h>
>  #include <linux/pci.h>
> -#include <linux/screen_info.h>
> +#include <linux/sysfb.h>
>  #include <linux/vgaarb.h>
>  
>  #include <asm/video.h>
> @@ -29,7 +29,7 @@ EXPORT_SYMBOL(pgprot_framebuffer);
>  bool video_is_primary_device(struct device *dev)
>  {
>  #ifdef CONFIG_SCREEN_INFO
> -	struct screen_info *si = &screen_info;
> +	struct screen_info *si = &sysfb_primary_display.screen;
>  	struct resource res[SCREEN_INFO_MAX_RESOURCES];
>  	ssize_t i, numres;
>  #endif
> diff --git a/drivers/firmware/efi/earlycon.c b/drivers/firmware/efi/earlycon.c
> index 42e3a173dac1..3d060d59968c 100644
> --- a/drivers/firmware/efi/earlycon.c
> +++ b/drivers/firmware/efi/earlycon.c
> @@ -9,7 +9,7 @@
>  #include <linux/io.h>
>  #include <linux/kernel.h>
>  #include <linux/serial_core.h>
> -#include <linux/screen_info.h>
> +#include <linux/sysfb.h>
>  #include <linux/string.h>
>  
>  #include <asm/early_ioremap.h>
> @@ -32,7 +32,7 @@ static void *efi_fb;
>   */
>  static int __init efi_earlycon_remap_fb(void)
>  {
> -	const struct screen_info *si = &screen_info;
> +	const struct screen_info *si = &sysfb_primary_display.screen;
>  
>  	/* bail if there is no bootconsole or it was unregistered already */
>  	if (!earlycon_console || !console_is_registered(earlycon_console))
> @@ -147,7 +147,7 @@ static void efi_earlycon_write_char(u32 *dst, unsigned char c, unsigned int h,
>  static void
>  efi_earlycon_write(struct console *con, const char *str, unsigned int num)
>  {
> -	const struct screen_info *si = &screen_info;
> +	const struct screen_info *si = &sysfb_primary_display.screen;
>  	u32 cur_efi_x = efi_x;
>  	unsigned int len;
>  	const char *s;
> @@ -227,7 +227,7 @@ void __init efi_earlycon_reprobe(void)
>  static int __init efi_earlycon_setup(struct earlycon_device *device,
>  				     const char *opt)
>  {
> -	const struct screen_info *si = &screen_info;
> +	const struct screen_info *si = &sysfb_primary_display.screen;
>  	u16 xres, yres;
>  	u32 i;
>  
> diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c
> index a65c2d5b9e7b..d1d418a34407 100644
> --- a/drivers/firmware/efi/efi-init.c
> +++ b/drivers/firmware/efi/efi-init.c
> @@ -19,7 +19,7 @@
>  #include <linux/of_address.h>
>  #include <linux/of_fdt.h>
>  #include <linux/platform_device.h>
> -#include <linux/screen_info.h>
> +#include <linux/sysfb.h>
>  
>  #include <asm/efi.h>
>  
> @@ -57,15 +57,15 @@ static phys_addr_t __init efi_to_phys(unsigned long addr)
>  extern __weak const efi_config_table_type_t efi_arch_tables[];
>  
>  /*
> - * x86 defines its own screen_info and uses it even without EFI,
> - * everything else can get it from here.
> + * x86 defines its own instance of sysfb_primary_display and uses
> + * it even without EFI, everything else can get them from here.
>   */
>  #if !defined(CONFIG_X86) && (defined(CONFIG_SYSFB) || defined(CONFIG_EFI_EARLYCON))
> -struct screen_info screen_info __section(".data");
> -EXPORT_SYMBOL_GPL(screen_info);
> +struct sysfb_display_info sysfb_primary_display __section(".data");
> +EXPORT_SYMBOL_GPL(sysfb_primary_display);
>  #endif
>  
> -static void __init init_screen_info(void)
> +static void __init init_primary_display(void)
>  {
>  	struct screen_info *si;
>  
> @@ -75,13 +75,13 @@ static void __init init_screen_info(void)
>  			pr_err("Could not map screen_info config table\n");
>  			return;
>  		}
> -		screen_info = *si;
> +		sysfb_primary_display.screen = *si;
>  		memset(si, 0, sizeof(*si));
>  		early_memunmap(si, sizeof(*si));
>  
> -		if (memblock_is_map_memory(screen_info.lfb_base))
> -			memblock_mark_nomap(screen_info.lfb_base,
> -					    screen_info.lfb_size);
> +		if (memblock_is_map_memory(sysfb_primary_display.screen.lfb_base))
> +			memblock_mark_nomap(sysfb_primary_display.screen.lfb_base,
> +					    sysfb_primary_display.screen.lfb_size);
>  
>  		if (IS_ENABLED(CONFIG_EFI_EARLYCON))
>  			efi_earlycon_reprobe();
> @@ -274,5 +274,5 @@ void __init efi_init(void)
>  	if (IS_ENABLED(CONFIG_X86) ||
>  	    IS_ENABLED(CONFIG_SYSFB) ||
>  	    IS_ENABLED(CONFIG_EFI_EARLYCON))
> -		init_screen_info();
> +		init_primary_display();
>  }
> diff --git a/drivers/firmware/efi/libstub/efi-stub-entry.c b/drivers/firmware/efi/libstub/efi-stub-entry.c
> index a6c049835190..401ecbbdf331 100644
> --- a/drivers/firmware/efi/libstub/efi-stub-entry.c
> +++ b/drivers/firmware/efi/libstub/efi-stub-entry.c
> @@ -1,13 +1,18 @@
>  // SPDX-License-Identifier: GPL-2.0-only
>  
>  #include <linux/efi.h>
> -#include <linux/screen_info.h>
> +#include <linux/sysfb.h>
>  
>  #include <asm/efi.h>
>  
>  #include "efistub.h"
>  
> -static unsigned long screen_info_offset;
> +static unsigned long kernel_image_offset;
> +
> +static void *kernel_image_addr(void *addr)
> +{
> +	return addr + kernel_image_offset;
> +}
>  
>  struct screen_info *alloc_screen_info(void)
>  {
> @@ -16,8 +21,11 @@ struct screen_info *alloc_screen_info(void)
>  
>  	if (IS_ENABLED(CONFIG_X86) ||
>  	    IS_ENABLED(CONFIG_EFI_EARLYCON) ||
> -	    IS_ENABLED(CONFIG_SYSFB))
> -		return (void *)&screen_info + screen_info_offset;
> +	    IS_ENABLED(CONFIG_SYSFB)) {
> +		struct sysfb_display_info *dpy = kernel_image_addr(&sysfb_primary_display);
> +
> +		return &dpy->screen;
> +	}
>  
>  	return NULL;
>  }
> @@ -73,7 +81,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
>  		return status;
>  	}
>  
> -	screen_info_offset = image_addr - (unsigned long)image->image_base;
> +	kernel_image_offset = image_addr - (unsigned long)image->image_base;
>  
>  	status = efi_stub_common(handle, image, image_addr, cmdline_ptr);
>  
> diff --git a/drivers/firmware/efi/sysfb_efi.c b/drivers/firmware/efi/sysfb_efi.c
> index 8e0f9d08397f..46ad95084b50 100644
> --- a/drivers/firmware/efi/sysfb_efi.c
> +++ b/drivers/firmware/efi/sysfb_efi.c
> @@ -176,7 +176,7 @@ static int __init efifb_set_system(struct screen_info *si, const struct dmi_syst
>  
>  static int __init efifb_set_system_callback(const struct dmi_system_id *id)
>  {
> -	return efifb_set_system(&screen_info, id);
> +	return efifb_set_system(&sysfb_primary_display.screen, id);
>  }
>  
>  #define EFIFB_DMI_SYSTEM_ID(vendor, name, enumid)		\
> @@ -316,7 +316,7 @@ static struct device_node *find_pci_overlap_node(void)
>  		}
>  
>  		for_each_of_pci_range(&parser, &range)
> -			if (efifb_overlaps_pci_range(&screen_info, &range))
> +			if (efifb_overlaps_pci_range(&sysfb_primary_display.screen, &range))
>  				return np;
>  	}
>  	return NULL;
> diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c
> index 916b28538a29..1f671f9219b0 100644
> --- a/drivers/firmware/sysfb.c
> +++ b/drivers/firmware/sysfb.c
> @@ -66,7 +66,7 @@ static bool sysfb_unregister(void)
>   */
>  void sysfb_disable(struct device *dev)
>  {
> -	struct screen_info *si = &screen_info;
> +	struct screen_info *si = &sysfb_primary_display.screen;
>  	struct device *parent;
>  
>  	mutex_lock(&disable_lock);
> @@ -92,7 +92,7 @@ EXPORT_SYMBOL_GPL(sysfb_disable);
>   */
>  bool sysfb_handles_screen_info(void)
>  {
> -	const struct screen_info *si = &screen_info;
> +	const struct screen_info *si = &sysfb_primary_display.screen;
>  
>  	return !!screen_info_video_type(si);
>  }
> @@ -141,7 +141,7 @@ static struct device *sysfb_parent_dev(const struct screen_info *si)
>  
>  static __init int sysfb_init(void)
>  {
> -	struct screen_info *si = &screen_info;
> +	struct screen_info *si = &sysfb_primary_display.screen;
>  	struct device *parent;
>  	unsigned int type;
>  	struct simplefb_platform_data mode;
> diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
> index a53af6fe81a6..9c937190be81 100644
> --- a/drivers/hv/vmbus_drv.c
> +++ b/drivers/hv/vmbus_drv.c
> @@ -29,7 +29,7 @@
>  #include <linux/delay.h>
>  #include <linux/panic_notifier.h>
>  #include <linux/ptrace.h>
> -#include <linux/screen_info.h>
> +#include <linux/sysfb.h>
>  #include <linux/efi.h>
>  #include <linux/random.h>
>  #include <linux/kernel.h>
> @@ -2340,8 +2340,8 @@ static void __maybe_unused vmbus_reserve_fb(void)
>  	if (efi_enabled(EFI_BOOT)) {
>  		/* Gen2 VM: get FB base from EFI framebuffer */
>  		if (IS_ENABLED(CONFIG_SYSFB)) {
> -			start = screen_info.lfb_base;
> -			size = max_t(__u32, screen_info.lfb_size, 0x800000);
> +			start = sysfb_primary_display.screen.lfb_base;
> +			size = max_t(__u32, sysfb_primary_display.screen.lfb_size, 0x800000);
>  		}
>  	} else {
>  		/* Gen1 VM: get FB base from PCI */
> diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c
> index 436fa7f4c387..805be9ea4a34 100644
> --- a/drivers/pci/vgaarb.c
> +++ b/drivers/pci/vgaarb.c
> @@ -26,7 +26,7 @@
>  #include <linux/poll.h>
>  #include <linux/miscdevice.h>
>  #include <linux/slab.h>
> -#include <linux/screen_info.h>
> +#include <linux/sysfb.h>
>  #include <linux/vt.h>
>  #include <linux/console.h>
>  #include <linux/acpi.h>
> @@ -557,7 +557,7 @@ EXPORT_SYMBOL(vga_put);
>  static bool vga_is_firmware_default(struct pci_dev *pdev)
>  {
>  #if defined CONFIG_X86
> -	return pdev == screen_info_pci_dev(&screen_info);
> +	return pdev == screen_info_pci_dev(&sysfb_primary_display.screen);
>  #else
>  	return false;
>  #endif
> diff --git a/drivers/video/screen_info_pci.c b/drivers/video/screen_info_pci.c
> index 66bfc1d0a6dc..8f34d8a74f09 100644
> --- a/drivers/video/screen_info_pci.c
> +++ b/drivers/video/screen_info_pci.c
> @@ -4,6 +4,7 @@
>  #include <linux/printk.h>
>  #include <linux/screen_info.h>
>  #include <linux/string.h>
> +#include <linux/sysfb.h>
>  
>  static struct pci_dev *screen_info_lfb_pdev;
>  static size_t screen_info_lfb_bar;
> @@ -26,7 +27,7 @@ static bool __screen_info_relocation_is_valid(const struct screen_info *si, stru
>  
>  void screen_info_apply_fixups(void)
>  {
> -	struct screen_info *si = &screen_info;
> +	struct screen_info *si = &sysfb_primary_display.screen;
>  
>  	if (screen_info_lfb_pdev) {
>  		struct resource *pr = &screen_info_lfb_pdev->resource[screen_info_lfb_bar];
> @@ -75,7 +76,7 @@ static void screen_info_fixup_lfb(struct pci_dev *pdev)
>  		.flags = IORESOURCE_MEM,
>  	};
>  	const struct resource *pr;
> -	const struct screen_info *si = &screen_info;
> +	const struct screen_info *si = &sysfb_primary_display.screen;
>  
>  	if (screen_info_lfb_pdev)
>  		return; // already found
> diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h
> index 1690706206e8..c022403c599a 100644
> --- a/include/linux/screen_info.h
> +++ b/include/linux/screen_info.h
> @@ -151,6 +151,4 @@ static inline struct pci_dev *screen_info_pci_dev(const struct screen_info *si)
>  }
>  #endif
>  
> -extern struct screen_info screen_info;
> -
>  #endif /* _SCREEN_INFO_H */
> diff --git a/include/linux/sysfb.h b/include/linux/sysfb.h
> index 8b37247528bf..e8bde392c690 100644
> --- a/include/linux/sysfb.h
> +++ b/include/linux/sysfb.h
> @@ -8,11 +8,10 @@
>   */
>  
>  #include <linux/err.h>
> +#include <linux/platform_data/simplefb.h>
>  #include <linux/screen_info.h>
>  #include <linux/types.h>
>  
> -#include <linux/platform_data/simplefb.h>
> -
>  struct device;
>  struct platform_device;
>  struct screen_info;
> @@ -65,6 +64,8 @@ struct sysfb_display_info {
>  	struct screen_info screen;
>  };
>  
> +extern struct sysfb_display_info sysfb_primary_display;
> +
>  #ifdef CONFIG_SYSFB
>  
>  void sysfb_disable(struct device *dev);
> -- 
> 2.51.1
> 

^ permalink raw reply

* Re: Oops when returning from hibernation with changed thunderbolt status
From: Kenneth Crudup @ 2025-11-24 18:02 UTC (permalink / raw)
  To: Lukas Wunner, Mika Westerberg
  Cc: Michael Guntsche, rafael.j.wysocki@intel.com, linux-pm, linux-efi
In-Reply-To: <aSGTghJyX-u-leL6@wunner.de>



On 11/22/25 02:42, Lukas Wunner wrote:

> Also the photo shows a UBSAN splat in drm/display/drm_mst_topology.c
> 220 msec before the oops, maybe it's related?

FWIW, this sounds really familiar (resume crashes if I changed TB docks 
between suspend and resume) and was getting an OOPS there I'd bisected to:

Resume OOPS from f6971d7427 ("drm/i915/mst: adapt 
intel_dp_mtp_tu_compute_config() for 128b/132b SST") if MST displays 
disconnected while suspended

... and this was fixed in 732b87a (Fix determining SST/MST mode during 
MTP TU state computation) back in 6.15 (which IIRC, is when your crashes 
started happening).

I wonder if this is related? Maybe reach out to the i915 guys?

-Kenny

-- 
Kenneth R. Crudup / Sr. SW Engineer, Scott County Consulting, Orange 
County CA


^ permalink raw reply

* Re: [PATCH v2 08/10] efi: Support EDID information
From: Ard Biesheuvel @ 2025-11-24 17:04 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: javierm, arnd, richard.lyu, x86, linux-arm-kernel, linux-kernel,
	linux-efi, loongarch, linux-riscv, dri-devel, linux-hyperv,
	linux-pci, linux-fbdev
In-Reply-To: <CAMj1kXFu4=L=ROVAaRORG5HMmYWHb6OXQf6pJ3yAZpeDmfmSeg@mail.gmail.com>

On Mon, 24 Nov 2025 at 18:01, Ard Biesheuvel <ardb@kernel.org> wrote:
>
> On Mon, 24 Nov 2025 at 17:52, Thomas Zimmermann <tzimmermann@suse.de> wrote:
> >
> > Add LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID to the list of config-table
> > UUIDs. Read sysfb_primary_display from the entry. The UUID has been
> > generated with uuidgen.
> >
> > Still support LINUX_EFI_SCREEN_INFO_TABLE_GUID as fallback in case an
> > older boot loader invokes the kernel.
> >
> > If CONFIG_FIRMWARE_EDID=n, EDID information is disabled.
> >
> > Make the Kconfig symbol CONFIG_FIRMWARE_EDID available with EFI. Setting
> > the value to 'n' disables EDID support.
> >
> > Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>
> Why are we adding a new config table again?
>
>

Note that LINUX_EFI_SCREEN_INFO_TABLE_GUID is internal ABI only
between the EFI stub and the core kernel.

^ permalink raw reply

* Re: [PATCH v2 08/10] efi: Support EDID information
From: Ard Biesheuvel @ 2025-11-24 17:01 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: javierm, arnd, richard.lyu, x86, linux-arm-kernel, linux-kernel,
	linux-efi, loongarch, linux-riscv, dri-devel, linux-hyperv,
	linux-pci, linux-fbdev
In-Reply-To: <20251124165116.502813-9-tzimmermann@suse.de>

On Mon, 24 Nov 2025 at 17:52, Thomas Zimmermann <tzimmermann@suse.de> wrote:
>
> Add LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID to the list of config-table
> UUIDs. Read sysfb_primary_display from the entry. The UUID has been
> generated with uuidgen.
>
> Still support LINUX_EFI_SCREEN_INFO_TABLE_GUID as fallback in case an
> older boot loader invokes the kernel.
>
> If CONFIG_FIRMWARE_EDID=n, EDID information is disabled.
>
> Make the Kconfig symbol CONFIG_FIRMWARE_EDID available with EFI. Setting
> the value to 'n' disables EDID support.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>

Why are we adding a new config table again?


> ---
>  arch/loongarch/kernel/efi.c     | 14 +++++++++++++-
>  drivers/firmware/efi/efi-init.c | 14 +++++++++++++-
>  drivers/firmware/efi/efi.c      |  2 ++
>  drivers/video/Kconfig           |  8 +++++---
>  include/linux/efi.h             |  8 +++++---
>  5 files changed, 38 insertions(+), 8 deletions(-)
>
> diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c
> index 1ef38036e8ae..2d90758e5037 100644
> --- a/arch/loongarch/kernel/efi.c
> +++ b/arch/loongarch/kernel/efi.c
> @@ -72,6 +72,7 @@ bool efi_poweroff_required(void)
>                 (acpi_gbl_reduced_hardware || acpi_no_s5);
>  }
>
> +unsigned long __initdata primary_display_table = EFI_INVALID_TABLE_ADDR;
>  unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;
>
>  #if defined(CONFIG_SYSFB) || defined(CONFIG_EFI_EARLYCON)
> @@ -81,7 +82,18 @@ EXPORT_SYMBOL_GPL(sysfb_primary_display);
>
>  static void __init init_primary_display(void)
>  {
> -       if (screen_info_table == EFI_INVALID_TABLE_ADDR) {
> +       if (primary_display_table != EFI_INVALID_TABLE_ADDR) {
> +               struct sysfb_display_info *dpy =
> +                       early_memremap(primary_display_table, sizeof(*dpy));
> +
> +               if (!dpy) {
> +                       pr_err("Could not map primary_display config table\n");
> +                       return;
> +               }
> +               sysfb_primary_display = *dpy;
> +               memset(dpy, 0, sizeof(*dpy));
> +               early_memunmap(dpy, sizeof(*dpy));
> +       } else if (screen_info_table != EFI_INVALID_TABLE_ADDR) {
>                 struct screen_info *si = early_memremap(screen_info_table, sizeof(*si));
>
>                 if (!si) {
> diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c
> index ca697d485116..0f167c0e058e 100644
> --- a/drivers/firmware/efi/efi-init.c
> +++ b/drivers/firmware/efi/efi-init.c
> @@ -23,6 +23,7 @@
>
>  #include <asm/efi.h>
>
> +unsigned long __initdata primary_display_table = EFI_INVALID_TABLE_ADDR;
>  unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;
>
>  static int __init is_memory(efi_memory_desc_t *md)
> @@ -67,7 +68,18 @@ EXPORT_SYMBOL_GPL(sysfb_primary_display);
>
>  static void __init init_primary_display(void)
>  {
> -       if (screen_info_table != EFI_INVALID_TABLE_ADDR) {
> +       if (primary_display_table != EFI_INVALID_TABLE_ADDR) {
> +               struct sysfb_display_info *dpy =
> +                       early_memremap(primary_display_table, sizeof(*dpy));
> +
> +               if (!dpy) {
> +                       pr_err("Could not map primary_display config table\n");
> +                       return;
> +               }
> +               sysfb_primary_display = *dpy;
> +               memset(dpy, 0, sizeof(*dpy));
> +               early_memunmap(dpy, sizeof(*dpy));
> +       } else if (screen_info_table != EFI_INVALID_TABLE_ADDR) {
>                 struct screen_info *si = early_memremap(screen_info_table, sizeof(*si));
>
>                 if (!si) {
> diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
> index a9070d00b833..c07f0878a4d6 100644
> --- a/drivers/firmware/efi/efi.c
> +++ b/drivers/firmware/efi/efi.c
> @@ -63,6 +63,7 @@ static unsigned long __initdata mem_reserve = EFI_INVALID_TABLE_ADDR;
>  static unsigned long __initdata rt_prop = EFI_INVALID_TABLE_ADDR;
>  static unsigned long __initdata initrd = EFI_INVALID_TABLE_ADDR;
>
> +extern unsigned long primary_display_table;
>  extern unsigned long screen_info_table;
>
>  struct mm_struct efi_mm = {
> @@ -641,6 +642,7 @@ static const efi_config_table_type_t common_tables[] __initconst = {
>         {LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID,   &efi.unaccepted,        "Unaccepted"    },
>  #endif
>  #ifdef CONFIG_EFI_GENERIC_STUB
> +       {LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID,  &primary_display_table                  },
>         {LINUX_EFI_SCREEN_INFO_TABLE_GUID,      &screen_info_table                      },
>  #endif
>         {},
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index d51777df12d1..f452fac90a9f 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -63,11 +63,13 @@ endif # HAS_IOMEM
>
>  config FIRMWARE_EDID
>         bool "Enable firmware EDID"
> -       depends on X86
> +       depends on EFI || X86
>         help
>           This enables access to the EDID transferred from the firmware.
> -         On x86, this is from the VESA BIOS. DRM display drivers will
> -         be able to export the information to userspace.
> +         On EFI systems, the EDID comes from the same device as the
> +         primary GOP. On x86 with BIOS, it comes from the VESA BIOS.
> +         DRM display drivers will be able to export the information
> +         to userspace.
>
>           Also enable this if DDC/I2C transfers do not work for your driver
>           and if you are using nvidiafb, i810fb or savagefb.
> diff --git a/include/linux/efi.h b/include/linux/efi.h
> index 2a43094e23f7..f645bcc66ee2 100644
> --- a/include/linux/efi.h
> +++ b/include/linux/efi.h
> @@ -406,11 +406,13 @@ void efi_native_runtime_setup(void);
>  #define EFI_CC_FINAL_EVENTS_TABLE_GUID         EFI_GUID(0xdd4a4648, 0x2de7, 0x4665, 0x96, 0x4d, 0x21, 0xd9, 0xef, 0x5f, 0xb4, 0x46)
>
>  /*
> - * This GUID is used to pass to the kernel proper the struct screen_info
> - * structure that was populated by the stub based on the GOP protocol instance
> - * associated with ConOut
> + * These GUIDs are used to pass to the kernel proper the info
> + * structures that were populated by the stub based on the GOP
> + * instance associated with ConOut.
>   */
> +#define LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID   EFI_GUID(0x8700a405, 0xcda4, 0x46d4,  0xb8, 0xc3, 0x04, 0xe5, 0xcd, 0xb4, 0x30, 0x21)
>  #define LINUX_EFI_SCREEN_INFO_TABLE_GUID       EFI_GUID(0xe03fc20a, 0x85dc, 0x406e,  0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95)
> +
>  #define LINUX_EFI_ARM_CPU_STATE_TABLE_GUID     EFI_GUID(0xef79e4aa, 0x3c3d, 0x4989,  0xb9, 0x02, 0x07, 0xa9, 0x43, 0xe5, 0x50, 0xd2)
>  #define LINUX_EFI_LOADER_ENTRY_GUID            EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf,  0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f)
>  #define LINUX_EFI_RANDOM_SEED_TABLE_GUID       EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2,  0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b)
> --
> 2.51.1
>

^ permalink raw reply

* [PATCH v2 08/10] efi: Support EDID information
From: Thomas Zimmermann @ 2025-11-24 16:40 UTC (permalink / raw)
  To: ardb, javierm, arnd, richard.lyu
  Cc: x86, linux-arm-kernel, linux-kernel, linux-efi, loongarch,
	linux-riscv, dri-devel, linux-hyperv, linux-pci, linux-fbdev,
	Thomas Zimmermann
In-Reply-To: <20251124165116.502813-1-tzimmermann@suse.de>

Add LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID to the list of config-table
UUIDs. Read sysfb_primary_display from the entry. The UUID has been
generated with uuidgen.

Still support LINUX_EFI_SCREEN_INFO_TABLE_GUID as fallback in case an
older boot loader invokes the kernel.

If CONFIG_FIRMWARE_EDID=n, EDID information is disabled.

Make the Kconfig symbol CONFIG_FIRMWARE_EDID available with EFI. Setting
the value to 'n' disables EDID support.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 arch/loongarch/kernel/efi.c     | 14 +++++++++++++-
 drivers/firmware/efi/efi-init.c | 14 +++++++++++++-
 drivers/firmware/efi/efi.c      |  2 ++
 drivers/video/Kconfig           |  8 +++++---
 include/linux/efi.h             |  8 +++++---
 5 files changed, 38 insertions(+), 8 deletions(-)

diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c
index 1ef38036e8ae..2d90758e5037 100644
--- a/arch/loongarch/kernel/efi.c
+++ b/arch/loongarch/kernel/efi.c
@@ -72,6 +72,7 @@ bool efi_poweroff_required(void)
 		(acpi_gbl_reduced_hardware || acpi_no_s5);
 }
 
+unsigned long __initdata primary_display_table = EFI_INVALID_TABLE_ADDR;
 unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;
 
 #if defined(CONFIG_SYSFB) || defined(CONFIG_EFI_EARLYCON)
@@ -81,7 +82,18 @@ EXPORT_SYMBOL_GPL(sysfb_primary_display);
 
 static void __init init_primary_display(void)
 {
-	if (screen_info_table == EFI_INVALID_TABLE_ADDR) {
+	if (primary_display_table != EFI_INVALID_TABLE_ADDR) {
+		struct sysfb_display_info *dpy =
+			early_memremap(primary_display_table, sizeof(*dpy));
+
+		if (!dpy) {
+			pr_err("Could not map primary_display config table\n");
+			return;
+		}
+		sysfb_primary_display = *dpy;
+		memset(dpy, 0, sizeof(*dpy));
+		early_memunmap(dpy, sizeof(*dpy));
+	} else if (screen_info_table != EFI_INVALID_TABLE_ADDR) {
 		struct screen_info *si = early_memremap(screen_info_table, sizeof(*si));
 
 		if (!si) {
diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c
index ca697d485116..0f167c0e058e 100644
--- a/drivers/firmware/efi/efi-init.c
+++ b/drivers/firmware/efi/efi-init.c
@@ -23,6 +23,7 @@
 
 #include <asm/efi.h>
 
+unsigned long __initdata primary_display_table = EFI_INVALID_TABLE_ADDR;
 unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;
 
 static int __init is_memory(efi_memory_desc_t *md)
@@ -67,7 +68,18 @@ EXPORT_SYMBOL_GPL(sysfb_primary_display);
 
 static void __init init_primary_display(void)
 {
-	if (screen_info_table != EFI_INVALID_TABLE_ADDR) {
+	if (primary_display_table != EFI_INVALID_TABLE_ADDR) {
+		struct sysfb_display_info *dpy =
+			early_memremap(primary_display_table, sizeof(*dpy));
+
+		if (!dpy) {
+			pr_err("Could not map primary_display config table\n");
+			return;
+		}
+		sysfb_primary_display = *dpy;
+		memset(dpy, 0, sizeof(*dpy));
+		early_memunmap(dpy, sizeof(*dpy));
+	} else if (screen_info_table != EFI_INVALID_TABLE_ADDR) {
 		struct screen_info *si = early_memremap(screen_info_table, sizeof(*si));
 
 		if (!si) {
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index a9070d00b833..c07f0878a4d6 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -63,6 +63,7 @@ static unsigned long __initdata mem_reserve = EFI_INVALID_TABLE_ADDR;
 static unsigned long __initdata rt_prop = EFI_INVALID_TABLE_ADDR;
 static unsigned long __initdata initrd = EFI_INVALID_TABLE_ADDR;
 
+extern unsigned long primary_display_table;
 extern unsigned long screen_info_table;
 
 struct mm_struct efi_mm = {
@@ -641,6 +642,7 @@ static const efi_config_table_type_t common_tables[] __initconst = {
 	{LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID,	&efi.unaccepted,	"Unaccepted"	},
 #endif
 #ifdef CONFIG_EFI_GENERIC_STUB
+	{LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID,	&primary_display_table			},
 	{LINUX_EFI_SCREEN_INFO_TABLE_GUID,	&screen_info_table			},
 #endif
 	{},
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index d51777df12d1..f452fac90a9f 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -63,11 +63,13 @@ endif # HAS_IOMEM
 
 config FIRMWARE_EDID
 	bool "Enable firmware EDID"
-	depends on X86
+	depends on EFI || X86
 	help
 	  This enables access to the EDID transferred from the firmware.
-	  On x86, this is from the VESA BIOS. DRM display drivers will
-	  be able to export the information to userspace.
+	  On EFI systems, the EDID comes from the same device as the
+	  primary GOP. On x86 with BIOS, it comes from the VESA BIOS.
+	  DRM display drivers will be able to export the information
+	  to userspace.
 
 	  Also enable this if DDC/I2C transfers do not work for your driver
 	  and if you are using nvidiafb, i810fb or savagefb.
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 2a43094e23f7..f645bcc66ee2 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -406,11 +406,13 @@ void efi_native_runtime_setup(void);
 #define EFI_CC_FINAL_EVENTS_TABLE_GUID		EFI_GUID(0xdd4a4648, 0x2de7, 0x4665, 0x96, 0x4d, 0x21, 0xd9, 0xef, 0x5f, 0xb4, 0x46)
 
 /*
- * This GUID is used to pass to the kernel proper the struct screen_info
- * structure that was populated by the stub based on the GOP protocol instance
- * associated with ConOut
+ * These GUIDs are used to pass to the kernel proper the info
+ * structures that were populated by the stub based on the GOP
+ * instance associated with ConOut.
  */
+#define LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID	EFI_GUID(0x8700a405, 0xcda4, 0x46d4,  0xb8, 0xc3, 0x04, 0xe5, 0xcd, 0xb4, 0x30, 0x21)
 #define LINUX_EFI_SCREEN_INFO_TABLE_GUID	EFI_GUID(0xe03fc20a, 0x85dc, 0x406e,  0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95)
+
 #define LINUX_EFI_ARM_CPU_STATE_TABLE_GUID	EFI_GUID(0xef79e4aa, 0x3c3d, 0x4989,  0xb9, 0x02, 0x07, 0xa9, 0x43, 0xe5, 0x50, 0xd2)
 #define LINUX_EFI_LOADER_ENTRY_GUID		EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf,  0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f)
 #define LINUX_EFI_RANDOM_SEED_TABLE_GUID	EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2,  0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b)
-- 
2.51.1


^ permalink raw reply related

* [PATCH v2 07/10] efi: Refactor init_primary_display() helpers
From: Thomas Zimmermann @ 2025-11-24 16:40 UTC (permalink / raw)
  To: ardb, javierm, arnd, richard.lyu
  Cc: x86, linux-arm-kernel, linux-kernel, linux-efi, loongarch,
	linux-riscv, dri-devel, linux-hyperv, linux-pci, linux-fbdev,
	Thomas Zimmermann
In-Reply-To: <20251124165116.502813-1-tzimmermann@suse.de>

Rework the kernel's init_primary_display() helpers to allow for later
support of additional config-table entries and EDID information. No
functional changes.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 arch/loongarch/kernel/efi.c     | 22 +++++++++++-----------
 drivers/firmware/efi/efi-init.c | 19 ++++++++++---------
 2 files changed, 21 insertions(+), 20 deletions(-)

diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c
index 638a392d2cd2..1ef38036e8ae 100644
--- a/arch/loongarch/kernel/efi.c
+++ b/arch/loongarch/kernel/efi.c
@@ -81,19 +81,19 @@ EXPORT_SYMBOL_GPL(sysfb_primary_display);
 
 static void __init init_primary_display(void)
 {
-	struct screen_info *si;
-
-	if (screen_info_table == EFI_INVALID_TABLE_ADDR)
-		return;
-
-	si = early_memremap(screen_info_table, sizeof(*si));
-	if (!si) {
-		pr_err("Could not map screen_info config table\n");
+	if (screen_info_table == EFI_INVALID_TABLE_ADDR) {
+		struct screen_info *si = early_memremap(screen_info_table, sizeof(*si));
+
+		if (!si) {
+			pr_err("Could not map screen_info config table\n");
+			return;
+		}
+		sysfb_primary_display.screen = *si;
+		memset(si, 0, sizeof(*si));
+		early_memunmap(si, sizeof(*si));
+	} else {
 		return;
 	}
-	sysfb_primary_display.screen = *si;
-	memset(si, 0, sizeof(*si));
-	early_memunmap(si, sizeof(*si));
 
 	memblock_reserve(__screen_info_lfb_base(&sysfb_primary_display.screen),
 			 sysfb_primary_display.screen.lfb_size);
diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c
index d1d418a34407..ca697d485116 100644
--- a/drivers/firmware/efi/efi-init.c
+++ b/drivers/firmware/efi/efi-init.c
@@ -67,10 +67,9 @@ EXPORT_SYMBOL_GPL(sysfb_primary_display);
 
 static void __init init_primary_display(void)
 {
-	struct screen_info *si;
-
 	if (screen_info_table != EFI_INVALID_TABLE_ADDR) {
-		si = early_memremap(screen_info_table, sizeof(*si));
+		struct screen_info *si = early_memremap(screen_info_table, sizeof(*si));
+
 		if (!si) {
 			pr_err("Could not map screen_info config table\n");
 			return;
@@ -78,14 +77,16 @@ static void __init init_primary_display(void)
 		sysfb_primary_display.screen = *si;
 		memset(si, 0, sizeof(*si));
 		early_memunmap(si, sizeof(*si));
+	} else {
+		return;
+	}
 
-		if (memblock_is_map_memory(sysfb_primary_display.screen.lfb_base))
-			memblock_mark_nomap(sysfb_primary_display.screen.lfb_base,
-					    sysfb_primary_display.screen.lfb_size);
+	if (memblock_is_map_memory(sysfb_primary_display.screen.lfb_base))
+		memblock_mark_nomap(sysfb_primary_display.screen.lfb_base,
+				    sysfb_primary_display.screen.lfb_size);
 
-		if (IS_ENABLED(CONFIG_EFI_EARLYCON))
-			efi_earlycon_reprobe();
-	}
+	if (IS_ENABLED(CONFIG_EFI_EARLYCON))
+		efi_earlycon_reprobe();
 }
 
 static int __init uefi_init(u64 efi_system_table)
-- 
2.51.1


^ permalink raw reply related

* [PATCH v2 06/10] sysfb: Move edid_info into sysfb_primary_display
From: Thomas Zimmermann @ 2025-11-24 16:40 UTC (permalink / raw)
  To: ardb, javierm, arnd, richard.lyu
  Cc: x86, linux-arm-kernel, linux-kernel, linux-efi, loongarch,
	linux-riscv, dri-devel, linux-hyperv, linux-pci, linux-fbdev,
	Thomas Zimmermann
In-Reply-To: <20251124165116.502813-1-tzimmermann@suse.de>

Move x86's edid_info into sysfb_primary_display as a new field named
edid. Adapt all users.

An instance of edid_info has only been defined on x86. With the move
into sysfb_primary_display, it becomes available on all architectures.
Therefore remove this contraint from CONFIG_FIRMWARE_EDID.

x86 fills the EDID data from boot_params.edid_info. DRM drivers pick
up the raw data and make it available to DRM clients. Replace the
drivers' references to edid_info and instead use the sysfb_display_info
as passed from sysfb.

v2:
- drop changes to CONFIG_FIRMWARE_EDID

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
---
 arch/x86/kernel/setup.c          | 6 +-----
 drivers/gpu/drm/sysfb/efidrm.c   | 5 ++---
 drivers/gpu/drm/sysfb/vesadrm.c  | 5 ++---
 drivers/video/fbdev/core/fbmon.c | 8 +++++---
 include/linux/sysfb.h            | 6 ++++++
 include/video/edid.h             | 4 ----
 6 files changed, 16 insertions(+), 18 deletions(-)

diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 675e4b9deb1f..d9bfe2032cd9 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -215,10 +215,6 @@ arch_initcall(init_x86_sysctl);
 
 struct sysfb_display_info sysfb_primary_display;
 EXPORT_SYMBOL(sysfb_primary_display);
-#if defined(CONFIG_FIRMWARE_EDID)
-struct edid_info edid_info;
-EXPORT_SYMBOL_GPL(edid_info);
-#endif
 
 extern int root_mountflags;
 
@@ -530,7 +526,7 @@ static void __init parse_boot_params(void)
 	ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev);
 	sysfb_primary_display.screen = boot_params.screen_info;
 #if defined(CONFIG_FIRMWARE_EDID)
-	edid_info = boot_params.edid_info;
+	sysfb_primary_display.edid = boot_params.edid_info;
 #endif
 #ifdef CONFIG_X86_32
 	apm_info.bios = boot_params.apm_bios_info;
diff --git a/drivers/gpu/drm/sysfb/efidrm.c b/drivers/gpu/drm/sysfb/efidrm.c
index 29533ae8fbbf..50e0aeef709c 100644
--- a/drivers/gpu/drm/sysfb/efidrm.c
+++ b/drivers/gpu/drm/sysfb/efidrm.c
@@ -24,7 +24,6 @@
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
 
-#include <video/edid.h>
 #include <video/pixel_format.h>
 
 #include "drm_sysfb_helper.h"
@@ -207,8 +206,8 @@ static struct efidrm_device *efidrm_device_create(struct drm_driver *drv,
 		&format->format, width, height, stride);
 
 #if defined(CONFIG_FIRMWARE_EDID)
-	if (drm_edid_header_is_valid(edid_info.dummy) == 8)
-		sysfb->edid = edid_info.dummy;
+	if (drm_edid_header_is_valid(dpy->edid.dummy) == 8)
+		sysfb->edid = dpy->edid.dummy;
 #endif
 	sysfb->fb_mode = drm_sysfb_mode(width, height, 0, 0);
 	sysfb->fb_format = format;
diff --git a/drivers/gpu/drm/sysfb/vesadrm.c b/drivers/gpu/drm/sysfb/vesadrm.c
index 16fc223f8c5b..0680638b8131 100644
--- a/drivers/gpu/drm/sysfb/vesadrm.c
+++ b/drivers/gpu/drm/sysfb/vesadrm.c
@@ -25,7 +25,6 @@
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
 
-#include <video/edid.h>
 #include <video/pixel_format.h>
 #include <video/vga.h>
 
@@ -474,8 +473,8 @@ static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv,
 	}
 
 #if defined(CONFIG_FIRMWARE_EDID)
-	if (drm_edid_header_is_valid(edid_info.dummy) == 8)
-		sysfb->edid = edid_info.dummy;
+	if (drm_edid_header_is_valid(dpy->edid.dummy) == 8)
+		sysfb->edid = dpy->edid.dummy;
 #endif
 	sysfb->fb_mode = drm_sysfb_mode(width, height, 0, 0);
 	sysfb->fb_format = format;
diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c
index 0a65bef01e3c..07df7e98f8a3 100644
--- a/drivers/video/fbdev/core/fbmon.c
+++ b/drivers/video/fbdev/core/fbmon.c
@@ -32,11 +32,13 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
-#include <video/edid.h>
+#include <linux/string_choices.h>
+#include <linux/sysfb.h>
+
 #include <video/of_videomode.h>
 #include <video/videomode.h>
+
 #include "../edid.h"
-#include <linux/string_choices.h>
 
 /*
  * EDID parser
@@ -1504,7 +1506,7 @@ const unsigned char *fb_firmware_edid(struct device *device)
 		res = &dev->resource[PCI_ROM_RESOURCE];
 
 	if (res && res->flags & IORESOURCE_ROM_SHADOW)
-		edid = edid_info.dummy;
+		edid = sysfb_primary_display.edid.dummy;
 
 	return edid;
 }
diff --git a/include/linux/sysfb.h b/include/linux/sysfb.h
index e8bde392c690..5226efde9ad4 100644
--- a/include/linux/sysfb.h
+++ b/include/linux/sysfb.h
@@ -12,6 +12,8 @@
 #include <linux/screen_info.h>
 #include <linux/types.h>
 
+#include <video/edid.h>
+
 struct device;
 struct platform_device;
 struct screen_info;
@@ -62,6 +64,10 @@ struct efifb_dmi_info {
 
 struct sysfb_display_info {
 	struct screen_info screen;
+
+#if defined(CONFIG_FIRMWARE_EDID)
+	struct edid_info edid;
+#endif
 };
 
 extern struct sysfb_display_info sysfb_primary_display;
diff --git a/include/video/edid.h b/include/video/edid.h
index c2b186b1933a..52aabb706032 100644
--- a/include/video/edid.h
+++ b/include/video/edid.h
@@ -4,8 +4,4 @@
 
 #include <uapi/video/edid.h>
 
-#if defined(CONFIG_FIRMWARE_EDID)
-extern struct edid_info edid_info;
-#endif
-
 #endif /* __linux_video_edid_h__ */
-- 
2.51.1


^ permalink raw reply related

* [PATCH v2 05/10] sysfb: Pass sysfb_primary_display to devices
From: Thomas Zimmermann @ 2025-11-24 16:40 UTC (permalink / raw)
  To: ardb, javierm, arnd, richard.lyu
  Cc: x86, linux-arm-kernel, linux-kernel, linux-efi, loongarch,
	linux-riscv, dri-devel, linux-hyperv, linux-pci, linux-fbdev,
	Thomas Zimmermann
In-Reply-To: <20251124165116.502813-1-tzimmermann@suse.de>

Instead of screen_info, store a copy of sysfb_primary_display as
device data. Pick it up in drivers. Later changes will add additional
data to the display info, such as EDID information.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
---
 drivers/firmware/sysfb.c        |  5 +++--
 drivers/gpu/drm/sysfb/efidrm.c  |  9 ++++++---
 drivers/gpu/drm/sysfb/vesadrm.c |  9 ++++++---
 drivers/video/fbdev/efifb.c     | 10 ++++++----
 drivers/video/fbdev/vesafb.c    | 10 ++++++----
 drivers/video/fbdev/vga16fb.c   |  8 +++++---
 6 files changed, 32 insertions(+), 19 deletions(-)

diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c
index 1f671f9219b0..8833582c1883 100644
--- a/drivers/firmware/sysfb.c
+++ b/drivers/firmware/sysfb.c
@@ -141,7 +141,8 @@ static struct device *sysfb_parent_dev(const struct screen_info *si)
 
 static __init int sysfb_init(void)
 {
-	struct screen_info *si = &sysfb_primary_display.screen;
+	struct sysfb_display_info *dpy = &sysfb_primary_display;
+	struct screen_info *si = &dpy->screen;
 	struct device *parent;
 	unsigned int type;
 	struct simplefb_platform_data mode;
@@ -202,7 +203,7 @@ static __init int sysfb_init(void)
 
 	sysfb_set_efifb_fwnode(si, pd);
 
-	ret = platform_device_add_data(pd, si, sizeof(*si));
+	ret = platform_device_add_data(pd, dpy, sizeof(*dpy));
 	if (ret)
 		goto err;
 
diff --git a/drivers/gpu/drm/sysfb/efidrm.c b/drivers/gpu/drm/sysfb/efidrm.c
index 1b683d55d6ea..29533ae8fbbf 100644
--- a/drivers/gpu/drm/sysfb/efidrm.c
+++ b/drivers/gpu/drm/sysfb/efidrm.c
@@ -4,7 +4,7 @@
 #include <linux/efi.h>
 #include <linux/limits.h>
 #include <linux/platform_device.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
 
 #include <drm/clients/drm_client_setup.h>
 #include <drm/drm_atomic.h>
@@ -141,6 +141,7 @@ static const struct drm_mode_config_funcs efidrm_mode_config_funcs = {
 static struct efidrm_device *efidrm_device_create(struct drm_driver *drv,
 						  struct platform_device *pdev)
 {
+	const struct sysfb_display_info *dpy;
 	const struct screen_info *si;
 	const struct drm_format_info *format;
 	int width, height, stride;
@@ -160,9 +161,11 @@ static struct efidrm_device *efidrm_device_create(struct drm_driver *drv,
 	size_t nformats;
 	int ret;
 
-	si = dev_get_platdata(&pdev->dev);
-	if (!si)
+	dpy = dev_get_platdata(&pdev->dev);
+	if (!dpy)
 		return ERR_PTR(-ENODEV);
+	si = &dpy->screen;
+
 	if (screen_info_video_type(si) != VIDEO_TYPE_EFI)
 		return ERR_PTR(-ENODEV);
 
diff --git a/drivers/gpu/drm/sysfb/vesadrm.c b/drivers/gpu/drm/sysfb/vesadrm.c
index 7b7b5ba26317..16fc223f8c5b 100644
--- a/drivers/gpu/drm/sysfb/vesadrm.c
+++ b/drivers/gpu/drm/sysfb/vesadrm.c
@@ -4,7 +4,7 @@
 #include <linux/ioport.h>
 #include <linux/limits.h>
 #include <linux/platform_device.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
 
 #include <drm/clients/drm_client_setup.h>
 #include <drm/drm_atomic.h>
@@ -391,6 +391,7 @@ static const struct drm_mode_config_funcs vesadrm_mode_config_funcs = {
 static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv,
 						    struct platform_device *pdev)
 {
+	const struct sysfb_display_info *dpy;
 	const struct screen_info *si;
 	const struct drm_format_info *format;
 	int width, height, stride;
@@ -410,9 +411,11 @@ static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv,
 	size_t nformats;
 	int ret;
 
-	si = dev_get_platdata(&pdev->dev);
-	if (!si)
+	dpy = dev_get_platdata(&pdev->dev);
+	if (!dpy)
 		return ERR_PTR(-ENODEV);
+	si = &dpy->screen;
+
 	if (screen_info_video_type(si) != VIDEO_TYPE_VLFB)
 		return ERR_PTR(-ENODEV);
 
diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c
index 0e1bd3dba255..47ebc0107209 100644
--- a/drivers/video/fbdev/efifb.c
+++ b/drivers/video/fbdev/efifb.c
@@ -15,7 +15,7 @@
 #include <linux/fb.h>
 #include <linux/platform_device.h>
 #include <linux/printk.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
 #include <video/vga.h>
 #include <asm/efi.h>
 #include <drm/drm_utils.h> /* For drm_get_panel_orientation_quirk */
@@ -345,6 +345,7 @@ ATTRIBUTE_GROUPS(efifb);
 
 static int efifb_probe(struct platform_device *dev)
 {
+	struct sysfb_display_info *dpy;
 	struct screen_info *si;
 	struct fb_info *info;
 	struct efifb_par *par;
@@ -360,10 +361,11 @@ static int efifb_probe(struct platform_device *dev)
 	 * driver. We get a copy of the attached screen_info, so that we can
 	 * modify its values without affecting later drivers.
 	 */
-	si = dev_get_platdata(&dev->dev);
-	if (!si)
+	dpy = dev_get_platdata(&dev->dev);
+	if (!dpy)
 		return -ENODEV;
-	si = devm_kmemdup(&dev->dev, si, sizeof(*si), GFP_KERNEL);
+
+	si = devm_kmemdup(&dev->dev, &dpy->screen, sizeof(*si), GFP_KERNEL);
 	if (!si)
 		return -ENOMEM;
 
diff --git a/drivers/video/fbdev/vesafb.c b/drivers/video/fbdev/vesafb.c
index f135033c22fb..f84f4db244bf 100644
--- a/drivers/video/fbdev/vesafb.c
+++ b/drivers/video/fbdev/vesafb.c
@@ -20,7 +20,7 @@
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
 #include <linux/io.h>
 
 #include <video/vga.h>
@@ -243,6 +243,7 @@ static int vesafb_setup(char *options)
 
 static int vesafb_probe(struct platform_device *dev)
 {
+	struct sysfb_display_info *dpy;
 	struct screen_info *si;
 	struct fb_info *info;
 	struct vesafb_par *par;
@@ -257,10 +258,11 @@ static int vesafb_probe(struct platform_device *dev)
 	 * driver. We get a copy of the attached screen_info, so that we can
 	 * modify its values without affecting later drivers.
 	 */
-	si = dev_get_platdata(&dev->dev);
-	if (!si)
+	dpy = dev_get_platdata(&dev->dev);
+	if (!dpy)
 		return -ENODEV;
-	si = devm_kmemdup(&dev->dev, si, sizeof(*si), GFP_KERNEL);
+
+	si = devm_kmemdup(&dev->dev, &dpy->screen, sizeof(*si), GFP_KERNEL);
 	if (!si)
 		return -ENOMEM;
 
diff --git a/drivers/video/fbdev/vga16fb.c b/drivers/video/fbdev/vga16fb.c
index 6b81337a4909..22085d3668e8 100644
--- a/drivers/video/fbdev/vga16fb.c
+++ b/drivers/video/fbdev/vga16fb.c
@@ -21,7 +21,7 @@
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
 
 #include <asm/io.h>
 #include <video/vga.h>
@@ -1305,15 +1305,17 @@ static const struct fb_ops vga16fb_ops = {
 
 static int vga16fb_probe(struct platform_device *dev)
 {
+	struct sysfb_display_info *dpy;
 	struct screen_info *si;
 	struct fb_info *info;
 	struct vga16fb_par *par;
 	int i;
 	int ret = 0;
 
-	si = dev_get_platdata(&dev->dev);
-	if (!si)
+	dpy = dev_get_platdata(&dev->dev);
+	if (!dpy)
 		return -ENODEV;
+	si = &dpy->screen;
 
 	ret = check_mode_supported(si);
 	if (ret)
-- 
2.51.1


^ permalink raw reply related

* [PATCH v2 10/10] efi: libstub: Simplify interfaces for primary_display
From: Thomas Zimmermann @ 2025-11-24 16:40 UTC (permalink / raw)
  To: ardb, javierm, arnd, richard.lyu
  Cc: x86, linux-arm-kernel, linux-kernel, linux-efi, loongarch,
	linux-riscv, dri-devel, linux-hyperv, linux-pci, linux-fbdev,
	Thomas Zimmermann
In-Reply-To: <20251124165116.502813-1-tzimmermann@suse.de>

Rename alloc_primary_display() and __alloc_primary_display(), clarify
free semantics to make interfaces easier to understand.

Rename alloc_primary_display() to lookup_primary_display() as it
does not necessarily allocate. Then rename __alloc_primary_display()
to the new alloc_primary_display(). The helper belongs to
free_primary_display), so it should be named without underscores.

The lookup helper does not necessarily allocate, so the output
parameter needs_free to indicate when free should be called. Pass
an argument through the calls to track this state. Put the free
handling into release_primary_display() for simplificy.

Also move the comment fro primary_display.c to efi-stub-entry.c,
where it now describes lookup_primary_display().

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/firmware/efi/libstub/efi-stub-entry.c | 23 +++++++++++++++++--
 drivers/firmware/efi/libstub/efi-stub.c       | 22 ++++++++++++------
 drivers/firmware/efi/libstub/efistub.h        |  2 +-
 .../firmware/efi/libstub/primary_display.c    | 17 +-------------
 drivers/firmware/efi/libstub/zboot.c          |  6 +++--
 5 files changed, 42 insertions(+), 28 deletions(-)

diff --git a/drivers/firmware/efi/libstub/efi-stub-entry.c b/drivers/firmware/efi/libstub/efi-stub-entry.c
index aa85e910fe59..3077b51fe0b2 100644
--- a/drivers/firmware/efi/libstub/efi-stub-entry.c
+++ b/drivers/firmware/efi/libstub/efi-stub-entry.c
@@ -14,10 +14,29 @@ static void *kernel_image_addr(void *addr)
 	return addr + kernel_image_offset;
 }
 
-struct sysfb_display_info *alloc_primary_display(void)
+/*
+ * There are two ways of populating the core kernel's sysfb_primary_display
+ * via the stub:
+ *
+ *   - using a configuration table, which relies on the EFI init code to
+ *     locate the table and copy the contents; or
+ *
+ *   - by linking directly to the core kernel's copy of the global symbol.
+ *
+ * The latter is preferred because it makes the EFIFB earlycon available very
+ * early, but it only works if the EFI stub is part of the core kernel image
+ * itself. The zboot decompressor can only use the configuration table
+ * approach.
+ */
+
+struct sysfb_display_info *lookup_primary_display(bool *needs_free)
 {
+	*needs_free = true;
+
 	if (IS_ENABLED(CONFIG_ARM))
-		return __alloc_primary_display();
+		return alloc_primary_display();
+
+	*needs_free = false;
 
 	if (IS_ENABLED(CONFIG_X86) ||
 	    IS_ENABLED(CONFIG_EFI_EARLYCON) ||
diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
index 42d6073bcd06..dc545f62c62b 100644
--- a/drivers/firmware/efi/libstub/efi-stub.c
+++ b/drivers/firmware/efi/libstub/efi-stub.c
@@ -51,14 +51,14 @@ static bool flat_va_mapping = (EFI_RT_VIRTUAL_OFFSET != 0);
 void __weak free_primary_display(struct sysfb_display_info *dpy)
 { }
 
-static struct sysfb_display_info *setup_primary_display(void)
+static struct sysfb_display_info *setup_primary_display(bool *dpy_needs_free)
 {
 	struct sysfb_display_info *dpy;
 	struct screen_info *screen = NULL;
 	struct edid_info *edid = NULL;
 	efi_status_t status;
 
-	dpy = alloc_primary_display();
+	dpy = lookup_primary_display(dpy_needs_free);
 	if (!dpy)
 		return NULL;
 	screen = &dpy->screen;
@@ -68,15 +68,22 @@ static struct sysfb_display_info *setup_primary_display(void)
 
 	status = efi_setup_graphics(screen, edid);
 	if (status != EFI_SUCCESS)
-		goto err_free_primary_display;
+		goto err___free_primary_display;
 
 	return dpy;
 
-err_free_primary_display:
-	free_primary_display(dpy);
+err___free_primary_display:
+	if (*dpy_needs_free)
+		free_primary_display(dpy);
 	return NULL;
 }
 
+static void release_primary_display(struct sysfb_display_info *dpy, bool dpy_needs_free)
+{
+	if (dpy && dpy_needs_free)
+		free_primary_display(dpy);
+}
+
 static void install_memreserve_table(void)
 {
 	struct linux_efi_memreserve *rsv;
@@ -156,13 +163,14 @@ efi_status_t efi_stub_common(efi_handle_t handle,
 			     char *cmdline_ptr)
 {
 	struct sysfb_display_info *dpy;
+	bool dpy_needs_free;
 	efi_status_t status;
 
 	status = check_platform_features();
 	if (status != EFI_SUCCESS)
 		return status;
 
-	dpy = setup_primary_display();
+	dpy = setup_primary_display(&dpy_needs_free);
 
 	efi_retrieve_eventlog();
 
@@ -182,7 +190,7 @@ efi_status_t efi_stub_common(efi_handle_t handle,
 
 	status = efi_boot_kernel(handle, image, image_addr, cmdline_ptr);
 
-	free_primary_display(dpy);
+	release_primary_display(dpy, dpy_needs_free);
 
 	return status;
 }
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 979a21818cc1..1503ffb82903 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -1176,8 +1176,8 @@ efi_enable_reset_attack_mitigation(void) { }
 
 void efi_retrieve_eventlog(void);
 
+struct sysfb_display_info *lookup_primary_display(bool *needs_free);
 struct sysfb_display_info *alloc_primary_display(void);
-struct sysfb_display_info *__alloc_primary_display(void);
 void free_primary_display(struct sysfb_display_info *dpy);
 
 void efi_cache_sync_image(unsigned long image_base,
diff --git a/drivers/firmware/efi/libstub/primary_display.c b/drivers/firmware/efi/libstub/primary_display.c
index cdaebab26514..34c54ac1e02a 100644
--- a/drivers/firmware/efi/libstub/primary_display.c
+++ b/drivers/firmware/efi/libstub/primary_display.c
@@ -7,24 +7,9 @@
 
 #include "efistub.h"
 
-/*
- * There are two ways of populating the core kernel's sysfb_primary_display
- * via the stub:
- *
- *   - using a configuration table, which relies on the EFI init code to
- *     locate the table and copy the contents; or
- *
- *   - by linking directly to the core kernel's copy of the global symbol.
- *
- * The latter is preferred because it makes the EFIFB earlycon available very
- * early, but it only works if the EFI stub is part of the core kernel image
- * itself. The zboot decompressor can only use the configuration table
- * approach.
- */
-
 static efi_guid_t primary_display_guid = LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID;
 
-struct sysfb_display_info *__alloc_primary_display(void)
+struct sysfb_display_info *alloc_primary_display(void)
 {
 	struct sysfb_display_info *dpy;
 	efi_status_t status;
diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c
index 4b76f74c56da..c1fd1fdbcb08 100644
--- a/drivers/firmware/efi/libstub/zboot.c
+++ b/drivers/firmware/efi/libstub/zboot.c
@@ -26,9 +26,11 @@ void __weak efi_cache_sync_image(unsigned long image_base,
 	// executable code loaded into memory to be safe for execution.
 }
 
-struct sysfb_display_info *alloc_primary_display(void)
+struct sysfb_display_info *lookup_primary_display(bool *needs_free)
 {
-	return __alloc_primary_display();
+	*needs_free = true;
+
+	return alloc_primary_display();
 }
 
 asmlinkage efi_status_t __efiapi
-- 
2.51.1


^ permalink raw reply related

* [PATCH v2 04/10] sysfb: Replace screen_info with sysfb_primary_display
From: Thomas Zimmermann @ 2025-11-24 16:40 UTC (permalink / raw)
  To: ardb, javierm, arnd, richard.lyu
  Cc: x86, linux-arm-kernel, linux-kernel, linux-efi, loongarch,
	linux-riscv, dri-devel, linux-hyperv, linux-pci, linux-fbdev,
	Thomas Zimmermann
In-Reply-To: <20251124165116.502813-1-tzimmermann@suse.de>

Replace the global screen_info with sysfb_primary_display of type
struct sysfb_display_info. Adapt all users of screen_info.

Instances of screen_info are defined for x86, loongarch and EFI,
with only one instance compiled into a specific build. Replace all
of them with sysfb_primary_display.

All existing users of screen_info are updated by pointing them to
sysfb_primary_display.screen instead. This introduces some churn to
the code, but has no impact on functionality.

Boot parameters and EFI config tables are unchanged. They transfer
screen_info as before. The logic in EFI's alloc_screen_info() changes
slightly, as it now returns the screen field of sysfb_primary_display.

v2:
- update comment
- rename init_screen_info() to init_primary_display()

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
---
 arch/arm64/kernel/image-vars.h                |  2 +-
 arch/loongarch/kernel/efi.c                   | 15 +++++++------
 arch/loongarch/kernel/image-vars.h            |  2 +-
 arch/riscv/kernel/image-vars.h                |  2 +-
 arch/x86/kernel/kexec-bzimage64.c             |  4 +++-
 arch/x86/kernel/setup.c                       | 10 +++++----
 arch/x86/video/video-common.c                 |  4 ++--
 drivers/firmware/efi/earlycon.c               |  8 +++----
 drivers/firmware/efi/efi-init.c               | 22 +++++++++----------
 drivers/firmware/efi/libstub/efi-stub-entry.c | 18 ++++++++++-----
 drivers/firmware/efi/sysfb_efi.c              |  4 ++--
 drivers/firmware/sysfb.c                      |  6 ++---
 drivers/hv/vmbus_drv.c                        |  6 ++---
 drivers/pci/vgaarb.c                          |  4 ++--
 drivers/video/screen_info_pci.c               |  5 +++--
 include/linux/screen_info.h                   |  2 --
 include/linux/sysfb.h                         |  5 +++--
 17 files changed, 66 insertions(+), 53 deletions(-)

diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h
index 85bc629270bd..d7b0d12b1015 100644
--- a/arch/arm64/kernel/image-vars.h
+++ b/arch/arm64/kernel/image-vars.h
@@ -38,7 +38,7 @@ PROVIDE(__efistub__end			= _end);
 PROVIDE(__efistub___inittext_end       	= __inittext_end);
 PROVIDE(__efistub__edata		= _edata);
 #if defined(CONFIG_EFI_EARLYCON) || defined(CONFIG_SYSFB)
-PROVIDE(__efistub_screen_info		= screen_info);
+PROVIDE(__efistub_sysfb_primary_display	= sysfb_primary_display);
 #endif
 PROVIDE(__efistub__ctype		= _ctype);
 
diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c
index 860a3bc030e0..638a392d2cd2 100644
--- a/arch/loongarch/kernel/efi.c
+++ b/arch/loongarch/kernel/efi.c
@@ -18,7 +18,7 @@
 #include <linux/kobject.h>
 #include <linux/memblock.h>
 #include <linux/reboot.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
 #include <linux/uaccess.h>
 
 #include <asm/early_ioremap.h>
@@ -75,11 +75,11 @@ bool efi_poweroff_required(void)
 unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;
 
 #if defined(CONFIG_SYSFB) || defined(CONFIG_EFI_EARLYCON)
-struct screen_info screen_info __section(".data");
-EXPORT_SYMBOL_GPL(screen_info);
+struct sysfb_display_info sysfb_primary_display __section(".data");
+EXPORT_SYMBOL_GPL(sysfb_primary_display);
 #endif
 
-static void __init init_screen_info(void)
+static void __init init_primary_display(void)
 {
 	struct screen_info *si;
 
@@ -91,11 +91,12 @@ static void __init init_screen_info(void)
 		pr_err("Could not map screen_info config table\n");
 		return;
 	}
-	screen_info = *si;
+	sysfb_primary_display.screen = *si;
 	memset(si, 0, sizeof(*si));
 	early_memunmap(si, sizeof(*si));
 
-	memblock_reserve(__screen_info_lfb_base(&screen_info), screen_info.lfb_size);
+	memblock_reserve(__screen_info_lfb_base(&sysfb_primary_display.screen),
+			 sysfb_primary_display.screen.lfb_size);
 }
 
 void __init efi_init(void)
@@ -127,7 +128,7 @@ void __init efi_init(void)
 	set_bit(EFI_CONFIG_TABLES, &efi.flags);
 
 	if (IS_ENABLED(CONFIG_EFI_EARLYCON) || IS_ENABLED(CONFIG_SYSFB))
-		init_screen_info();
+		init_primary_display();
 
 	if (boot_memmap == EFI_INVALID_TABLE_ADDR)
 		return;
diff --git a/arch/loongarch/kernel/image-vars.h b/arch/loongarch/kernel/image-vars.h
index 41ddcf56d21c..e557ebd46c2b 100644
--- a/arch/loongarch/kernel/image-vars.h
+++ b/arch/loongarch/kernel/image-vars.h
@@ -12,7 +12,7 @@ __efistub_kernel_entry		= kernel_entry;
 __efistub_kernel_asize		= kernel_asize;
 __efistub_kernel_fsize		= kernel_fsize;
 #if defined(CONFIG_EFI_EARLYCON) || defined(CONFIG_SYSFB)
-__efistub_screen_info		= screen_info;
+__efistub_sysfb_primary_display	= sysfb_primary_display;
 #endif
 
 #endif
diff --git a/arch/riscv/kernel/image-vars.h b/arch/riscv/kernel/image-vars.h
index 3df30dd1c458..3bd9d06a8b8f 100644
--- a/arch/riscv/kernel/image-vars.h
+++ b/arch/riscv/kernel/image-vars.h
@@ -29,7 +29,7 @@ __efistub__end			= _end;
 __efistub__edata		= _edata;
 __efistub___init_text_end	= __init_text_end;
 #if defined(CONFIG_EFI_EARLYCON) || defined(CONFIG_SYSFB)
-__efistub_screen_info		= screen_info;
+__efistub_sysfb_primary_display	= sysfb_primary_display;
 #endif
 
 #endif
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index c3244ac680d1..7508d0ccc740 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -20,6 +20,7 @@
 #include <linux/of_fdt.h>
 #include <linux/efi.h>
 #include <linux/random.h>
+#include <linux/sysfb.h>
 
 #include <asm/bootparam.h>
 #include <asm/setup.h>
@@ -303,7 +304,8 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params,
 	params->hdr.hardware_subarch = boot_params.hdr.hardware_subarch;
 
 	/* Copying screen_info will do? */
-	memcpy(&params->screen_info, &screen_info, sizeof(struct screen_info));
+	memcpy(&params->screen_info, &sysfb_primary_display.screen,
+	       sizeof(sysfb_primary_display.screen));
 
 	/* Fill in memsize later */
 	params->screen_info.ext_mem_k = 0;
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 1b2edd07a3e1..675e4b9deb1f 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -22,6 +22,7 @@
 #include <linux/random.h>
 #include <linux/root_dev.h>
 #include <linux/static_call.h>
+#include <linux/sysfb.h>
 #include <linux/swiotlb.h>
 #include <linux/tboot.h>
 #include <linux/usb/xhci-dbgp.h>
@@ -211,8 +212,9 @@ arch_initcall(init_x86_sysctl);
 /*
  * Setup options
  */
-struct screen_info screen_info;
-EXPORT_SYMBOL(screen_info);
+
+struct sysfb_display_info sysfb_primary_display;
+EXPORT_SYMBOL(sysfb_primary_display);
 #if defined(CONFIG_FIRMWARE_EDID)
 struct edid_info edid_info;
 EXPORT_SYMBOL_GPL(edid_info);
@@ -526,7 +528,7 @@ static void __init parse_setup_data(void)
 static void __init parse_boot_params(void)
 {
 	ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev);
-	screen_info = boot_params.screen_info;
+	sysfb_primary_display.screen = boot_params.screen_info;
 #if defined(CONFIG_FIRMWARE_EDID)
 	edid_info = boot_params.edid_info;
 #endif
@@ -1254,7 +1256,7 @@ void __init setup_arch(char **cmdline_p)
 #ifdef CONFIG_VT
 #if defined(CONFIG_VGA_CONSOLE)
 	if (!efi_enabled(EFI_BOOT) || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
-		vgacon_register_screen(&screen_info);
+		vgacon_register_screen(&sysfb_primary_display.screen);
 #endif
 #endif
 	x86_init.oem.banner();
diff --git a/arch/x86/video/video-common.c b/arch/x86/video/video-common.c
index e0aeee99bc99..152789f00fcd 100644
--- a/arch/x86/video/video-common.c
+++ b/arch/x86/video/video-common.c
@@ -9,7 +9,7 @@
 
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
 #include <linux/vgaarb.h>
 
 #include <asm/video.h>
@@ -29,7 +29,7 @@ EXPORT_SYMBOL(pgprot_framebuffer);
 bool video_is_primary_device(struct device *dev)
 {
 #ifdef CONFIG_SCREEN_INFO
-	struct screen_info *si = &screen_info;
+	struct screen_info *si = &sysfb_primary_display.screen;
 	struct resource res[SCREEN_INFO_MAX_RESOURCES];
 	ssize_t i, numres;
 #endif
diff --git a/drivers/firmware/efi/earlycon.c b/drivers/firmware/efi/earlycon.c
index 42e3a173dac1..3d060d59968c 100644
--- a/drivers/firmware/efi/earlycon.c
+++ b/drivers/firmware/efi/earlycon.c
@@ -9,7 +9,7 @@
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/serial_core.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
 #include <linux/string.h>
 
 #include <asm/early_ioremap.h>
@@ -32,7 +32,7 @@ static void *efi_fb;
  */
 static int __init efi_earlycon_remap_fb(void)
 {
-	const struct screen_info *si = &screen_info;
+	const struct screen_info *si = &sysfb_primary_display.screen;
 
 	/* bail if there is no bootconsole or it was unregistered already */
 	if (!earlycon_console || !console_is_registered(earlycon_console))
@@ -147,7 +147,7 @@ static void efi_earlycon_write_char(u32 *dst, unsigned char c, unsigned int h,
 static void
 efi_earlycon_write(struct console *con, const char *str, unsigned int num)
 {
-	const struct screen_info *si = &screen_info;
+	const struct screen_info *si = &sysfb_primary_display.screen;
 	u32 cur_efi_x = efi_x;
 	unsigned int len;
 	const char *s;
@@ -227,7 +227,7 @@ void __init efi_earlycon_reprobe(void)
 static int __init efi_earlycon_setup(struct earlycon_device *device,
 				     const char *opt)
 {
-	const struct screen_info *si = &screen_info;
+	const struct screen_info *si = &sysfb_primary_display.screen;
 	u16 xres, yres;
 	u32 i;
 
diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c
index a65c2d5b9e7b..d1d418a34407 100644
--- a/drivers/firmware/efi/efi-init.c
+++ b/drivers/firmware/efi/efi-init.c
@@ -19,7 +19,7 @@
 #include <linux/of_address.h>
 #include <linux/of_fdt.h>
 #include <linux/platform_device.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
 
 #include <asm/efi.h>
 
@@ -57,15 +57,15 @@ static phys_addr_t __init efi_to_phys(unsigned long addr)
 extern __weak const efi_config_table_type_t efi_arch_tables[];
 
 /*
- * x86 defines its own screen_info and uses it even without EFI,
- * everything else can get it from here.
+ * x86 defines its own instance of sysfb_primary_display and uses
+ * it even without EFI, everything else can get them from here.
  */
 #if !defined(CONFIG_X86) && (defined(CONFIG_SYSFB) || defined(CONFIG_EFI_EARLYCON))
-struct screen_info screen_info __section(".data");
-EXPORT_SYMBOL_GPL(screen_info);
+struct sysfb_display_info sysfb_primary_display __section(".data");
+EXPORT_SYMBOL_GPL(sysfb_primary_display);
 #endif
 
-static void __init init_screen_info(void)
+static void __init init_primary_display(void)
 {
 	struct screen_info *si;
 
@@ -75,13 +75,13 @@ static void __init init_screen_info(void)
 			pr_err("Could not map screen_info config table\n");
 			return;
 		}
-		screen_info = *si;
+		sysfb_primary_display.screen = *si;
 		memset(si, 0, sizeof(*si));
 		early_memunmap(si, sizeof(*si));
 
-		if (memblock_is_map_memory(screen_info.lfb_base))
-			memblock_mark_nomap(screen_info.lfb_base,
-					    screen_info.lfb_size);
+		if (memblock_is_map_memory(sysfb_primary_display.screen.lfb_base))
+			memblock_mark_nomap(sysfb_primary_display.screen.lfb_base,
+					    sysfb_primary_display.screen.lfb_size);
 
 		if (IS_ENABLED(CONFIG_EFI_EARLYCON))
 			efi_earlycon_reprobe();
@@ -274,5 +274,5 @@ void __init efi_init(void)
 	if (IS_ENABLED(CONFIG_X86) ||
 	    IS_ENABLED(CONFIG_SYSFB) ||
 	    IS_ENABLED(CONFIG_EFI_EARLYCON))
-		init_screen_info();
+		init_primary_display();
 }
diff --git a/drivers/firmware/efi/libstub/efi-stub-entry.c b/drivers/firmware/efi/libstub/efi-stub-entry.c
index a6c049835190..401ecbbdf331 100644
--- a/drivers/firmware/efi/libstub/efi-stub-entry.c
+++ b/drivers/firmware/efi/libstub/efi-stub-entry.c
@@ -1,13 +1,18 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
 #include <linux/efi.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
 
 #include <asm/efi.h>
 
 #include "efistub.h"
 
-static unsigned long screen_info_offset;
+static unsigned long kernel_image_offset;
+
+static void *kernel_image_addr(void *addr)
+{
+	return addr + kernel_image_offset;
+}
 
 struct screen_info *alloc_screen_info(void)
 {
@@ -16,8 +21,11 @@ struct screen_info *alloc_screen_info(void)
 
 	if (IS_ENABLED(CONFIG_X86) ||
 	    IS_ENABLED(CONFIG_EFI_EARLYCON) ||
-	    IS_ENABLED(CONFIG_SYSFB))
-		return (void *)&screen_info + screen_info_offset;
+	    IS_ENABLED(CONFIG_SYSFB)) {
+		struct sysfb_display_info *dpy = kernel_image_addr(&sysfb_primary_display);
+
+		return &dpy->screen;
+	}
 
 	return NULL;
 }
@@ -73,7 +81,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
 		return status;
 	}
 
-	screen_info_offset = image_addr - (unsigned long)image->image_base;
+	kernel_image_offset = image_addr - (unsigned long)image->image_base;
 
 	status = efi_stub_common(handle, image, image_addr, cmdline_ptr);
 
diff --git a/drivers/firmware/efi/sysfb_efi.c b/drivers/firmware/efi/sysfb_efi.c
index 8e0f9d08397f..46ad95084b50 100644
--- a/drivers/firmware/efi/sysfb_efi.c
+++ b/drivers/firmware/efi/sysfb_efi.c
@@ -176,7 +176,7 @@ static int __init efifb_set_system(struct screen_info *si, const struct dmi_syst
 
 static int __init efifb_set_system_callback(const struct dmi_system_id *id)
 {
-	return efifb_set_system(&screen_info, id);
+	return efifb_set_system(&sysfb_primary_display.screen, id);
 }
 
 #define EFIFB_DMI_SYSTEM_ID(vendor, name, enumid)		\
@@ -316,7 +316,7 @@ static struct device_node *find_pci_overlap_node(void)
 		}
 
 		for_each_of_pci_range(&parser, &range)
-			if (efifb_overlaps_pci_range(&screen_info, &range))
+			if (efifb_overlaps_pci_range(&sysfb_primary_display.screen, &range))
 				return np;
 	}
 	return NULL;
diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c
index 916b28538a29..1f671f9219b0 100644
--- a/drivers/firmware/sysfb.c
+++ b/drivers/firmware/sysfb.c
@@ -66,7 +66,7 @@ static bool sysfb_unregister(void)
  */
 void sysfb_disable(struct device *dev)
 {
-	struct screen_info *si = &screen_info;
+	struct screen_info *si = &sysfb_primary_display.screen;
 	struct device *parent;
 
 	mutex_lock(&disable_lock);
@@ -92,7 +92,7 @@ EXPORT_SYMBOL_GPL(sysfb_disable);
  */
 bool sysfb_handles_screen_info(void)
 {
-	const struct screen_info *si = &screen_info;
+	const struct screen_info *si = &sysfb_primary_display.screen;
 
 	return !!screen_info_video_type(si);
 }
@@ -141,7 +141,7 @@ static struct device *sysfb_parent_dev(const struct screen_info *si)
 
 static __init int sysfb_init(void)
 {
-	struct screen_info *si = &screen_info;
+	struct screen_info *si = &sysfb_primary_display.screen;
 	struct device *parent;
 	unsigned int type;
 	struct simplefb_platform_data mode;
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index a53af6fe81a6..9c937190be81 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -29,7 +29,7 @@
 #include <linux/delay.h>
 #include <linux/panic_notifier.h>
 #include <linux/ptrace.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
 #include <linux/efi.h>
 #include <linux/random.h>
 #include <linux/kernel.h>
@@ -2340,8 +2340,8 @@ static void __maybe_unused vmbus_reserve_fb(void)
 	if (efi_enabled(EFI_BOOT)) {
 		/* Gen2 VM: get FB base from EFI framebuffer */
 		if (IS_ENABLED(CONFIG_SYSFB)) {
-			start = screen_info.lfb_base;
-			size = max_t(__u32, screen_info.lfb_size, 0x800000);
+			start = sysfb_primary_display.screen.lfb_base;
+			size = max_t(__u32, sysfb_primary_display.screen.lfb_size, 0x800000);
 		}
 	} else {
 		/* Gen1 VM: get FB base from PCI */
diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c
index 436fa7f4c387..805be9ea4a34 100644
--- a/drivers/pci/vgaarb.c
+++ b/drivers/pci/vgaarb.c
@@ -26,7 +26,7 @@
 #include <linux/poll.h>
 #include <linux/miscdevice.h>
 #include <linux/slab.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
 #include <linux/vt.h>
 #include <linux/console.h>
 #include <linux/acpi.h>
@@ -557,7 +557,7 @@ EXPORT_SYMBOL(vga_put);
 static bool vga_is_firmware_default(struct pci_dev *pdev)
 {
 #if defined CONFIG_X86
-	return pdev == screen_info_pci_dev(&screen_info);
+	return pdev == screen_info_pci_dev(&sysfb_primary_display.screen);
 #else
 	return false;
 #endif
diff --git a/drivers/video/screen_info_pci.c b/drivers/video/screen_info_pci.c
index 66bfc1d0a6dc..8f34d8a74f09 100644
--- a/drivers/video/screen_info_pci.c
+++ b/drivers/video/screen_info_pci.c
@@ -4,6 +4,7 @@
 #include <linux/printk.h>
 #include <linux/screen_info.h>
 #include <linux/string.h>
+#include <linux/sysfb.h>
 
 static struct pci_dev *screen_info_lfb_pdev;
 static size_t screen_info_lfb_bar;
@@ -26,7 +27,7 @@ static bool __screen_info_relocation_is_valid(const struct screen_info *si, stru
 
 void screen_info_apply_fixups(void)
 {
-	struct screen_info *si = &screen_info;
+	struct screen_info *si = &sysfb_primary_display.screen;
 
 	if (screen_info_lfb_pdev) {
 		struct resource *pr = &screen_info_lfb_pdev->resource[screen_info_lfb_bar];
@@ -75,7 +76,7 @@ static void screen_info_fixup_lfb(struct pci_dev *pdev)
 		.flags = IORESOURCE_MEM,
 	};
 	const struct resource *pr;
-	const struct screen_info *si = &screen_info;
+	const struct screen_info *si = &sysfb_primary_display.screen;
 
 	if (screen_info_lfb_pdev)
 		return; // already found
diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h
index 1690706206e8..c022403c599a 100644
--- a/include/linux/screen_info.h
+++ b/include/linux/screen_info.h
@@ -151,6 +151,4 @@ static inline struct pci_dev *screen_info_pci_dev(const struct screen_info *si)
 }
 #endif
 
-extern struct screen_info screen_info;
-
 #endif /* _SCREEN_INFO_H */
diff --git a/include/linux/sysfb.h b/include/linux/sysfb.h
index 8b37247528bf..e8bde392c690 100644
--- a/include/linux/sysfb.h
+++ b/include/linux/sysfb.h
@@ -8,11 +8,10 @@
  */
 
 #include <linux/err.h>
+#include <linux/platform_data/simplefb.h>
 #include <linux/screen_info.h>
 #include <linux/types.h>
 
-#include <linux/platform_data/simplefb.h>
-
 struct device;
 struct platform_device;
 struct screen_info;
@@ -65,6 +64,8 @@ struct sysfb_display_info {
 	struct screen_info screen;
 };
 
+extern struct sysfb_display_info sysfb_primary_display;
+
 #ifdef CONFIG_SYSFB
 
 void sysfb_disable(struct device *dev);
-- 
2.51.1


^ permalink raw reply related

* [PATCH v2 09/10] efi: libstub: Transfer EDID to kernel
From: Thomas Zimmermann @ 2025-11-24 16:40 UTC (permalink / raw)
  To: ardb, javierm, arnd, richard.lyu
  Cc: x86, linux-arm-kernel, linux-kernel, linux-efi, loongarch,
	linux-riscv, dri-devel, linux-hyperv, linux-pci, linux-fbdev,
	Thomas Zimmermann
In-Reply-To: <20251124165116.502813-1-tzimmermann@suse.de>

Replace struct screen_info with struct sysfb_display_info from the
kernel's sysfb_primary_display and rename functions accordingly.
Transfer the it to the runtime kernel using the kernel's global state
or the config-table entry LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID.

Also rename screen_info.c to primary_display.c and adapt the contained
comment according to the changes.

With CONFIG_FIRMWARE_EDID=y, libstub now transfers the GOP device's
EDID information to the kernel.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/firmware/efi/libstub/Makefile         |  2 +-
 drivers/firmware/efi/libstub/efi-stub-entry.c | 11 ++--
 drivers/firmware/efi/libstub/efi-stub.c       | 41 +++++++++-----
 drivers/firmware/efi/libstub/efistub.h        |  7 ++-
 .../firmware/efi/libstub/primary_display.c    | 56 +++++++++++++++++++
 drivers/firmware/efi/libstub/screen_info.c    | 53 ------------------
 drivers/firmware/efi/libstub/zboot.c          |  4 +-
 7 files changed, 93 insertions(+), 81 deletions(-)
 create mode 100644 drivers/firmware/efi/libstub/primary_display.c
 delete mode 100644 drivers/firmware/efi/libstub/screen_info.c

diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index 7d15a85d579f..e386ffd009b7 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -80,7 +80,7 @@ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
 	$(call if_changed_rule,cc_o_c)
 
 lib-$(CONFIG_EFI_GENERIC_STUB)	+= efi-stub.o string.o intrinsics.o systable.o \
-				   screen_info.o efi-stub-entry.o
+				   primary_display.o efi-stub-entry.o
 
 lib-$(CONFIG_ARM)		+= arm32-stub.o
 lib-$(CONFIG_ARM64)		+= kaslr.o arm64.o arm64-stub.o smbios.o
diff --git a/drivers/firmware/efi/libstub/efi-stub-entry.c b/drivers/firmware/efi/libstub/efi-stub-entry.c
index 401ecbbdf331..aa85e910fe59 100644
--- a/drivers/firmware/efi/libstub/efi-stub-entry.c
+++ b/drivers/firmware/efi/libstub/efi-stub-entry.c
@@ -14,18 +14,15 @@ static void *kernel_image_addr(void *addr)
 	return addr + kernel_image_offset;
 }
 
-struct screen_info *alloc_screen_info(void)
+struct sysfb_display_info *alloc_primary_display(void)
 {
 	if (IS_ENABLED(CONFIG_ARM))
-		return __alloc_screen_info();
+		return __alloc_primary_display();
 
 	if (IS_ENABLED(CONFIG_X86) ||
 	    IS_ENABLED(CONFIG_EFI_EARLYCON) ||
-	    IS_ENABLED(CONFIG_SYSFB)) {
-		struct sysfb_display_info *dpy = kernel_image_addr(&sysfb_primary_display);
-
-		return &dpy->screen;
-	}
+	    IS_ENABLED(CONFIG_SYSFB))
+		return kernel_image_addr(&sysfb_primary_display);
 
 	return NULL;
 }
diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
index 9cb814c5ba1b..42d6073bcd06 100644
--- a/drivers/firmware/efi/libstub/efi-stub.c
+++ b/drivers/firmware/efi/libstub/efi-stub.c
@@ -10,7 +10,7 @@
  */
 
 #include <linux/efi.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
 #include <asm/efi.h>
 
 #include "efistub.h"
@@ -48,23 +48,33 @@
 static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
 static bool flat_va_mapping = (EFI_RT_VIRTUAL_OFFSET != 0);
 
-void __weak free_screen_info(struct screen_info *si)
-{
-}
+void __weak free_primary_display(struct sysfb_display_info *dpy)
+{ }
 
-static struct screen_info *setup_graphics(void)
+static struct sysfb_display_info *setup_primary_display(void)
 {
-	struct screen_info *si, tmp = {};
+	struct sysfb_display_info *dpy;
+	struct screen_info *screen = NULL;
+	struct edid_info *edid = NULL;
+	efi_status_t status;
 
-	if (efi_setup_graphics(&tmp, NULL) != EFI_SUCCESS)
+	dpy = alloc_primary_display();
+	if (!dpy)
 		return NULL;
+	screen = &dpy->screen;
+#if defined(CONFIG_FIRMWARE_EDID)
+	edid = &dpy->edid;
+#endif
 
-	si = alloc_screen_info();
-	if (!si)
-		return NULL;
+	status = efi_setup_graphics(screen, edid);
+	if (status != EFI_SUCCESS)
+		goto err_free_primary_display;
 
-	*si = tmp;
-	return si;
+	return dpy;
+
+err_free_primary_display:
+	free_primary_display(dpy);
+	return NULL;
 }
 
 static void install_memreserve_table(void)
@@ -145,14 +155,14 @@ efi_status_t efi_stub_common(efi_handle_t handle,
 			     unsigned long image_addr,
 			     char *cmdline_ptr)
 {
-	struct screen_info *si;
+	struct sysfb_display_info *dpy;
 	efi_status_t status;
 
 	status = check_platform_features();
 	if (status != EFI_SUCCESS)
 		return status;
 
-	si = setup_graphics();
+	dpy = setup_primary_display();
 
 	efi_retrieve_eventlog();
 
@@ -172,7 +182,8 @@ efi_status_t efi_stub_common(efi_handle_t handle,
 
 	status = efi_boot_kernel(handle, image, image_addr, cmdline_ptr);
 
-	free_screen_info(si);
+	free_primary_display(dpy);
+
 	return status;
 }
 
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index b2fb0c3fa721..979a21818cc1 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -36,6 +36,7 @@
 
 struct edid_info;
 struct screen_info;
+struct sysfb_display_info;
 
 extern bool efi_no5lvl;
 extern bool efi_nochunk;
@@ -1175,9 +1176,9 @@ efi_enable_reset_attack_mitigation(void) { }
 
 void efi_retrieve_eventlog(void);
 
-struct screen_info *alloc_screen_info(void);
-struct screen_info *__alloc_screen_info(void);
-void free_screen_info(struct screen_info *si);
+struct sysfb_display_info *alloc_primary_display(void);
+struct sysfb_display_info *__alloc_primary_display(void);
+void free_primary_display(struct sysfb_display_info *dpy);
 
 void efi_cache_sync_image(unsigned long image_base,
 			  unsigned long alloc_size);
diff --git a/drivers/firmware/efi/libstub/primary_display.c b/drivers/firmware/efi/libstub/primary_display.c
new file mode 100644
index 000000000000..cdaebab26514
--- /dev/null
+++ b/drivers/firmware/efi/libstub/primary_display.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/efi.h>
+#include <linux/sysfb.h>
+
+#include <asm/efi.h>
+
+#include "efistub.h"
+
+/*
+ * There are two ways of populating the core kernel's sysfb_primary_display
+ * via the stub:
+ *
+ *   - using a configuration table, which relies on the EFI init code to
+ *     locate the table and copy the contents; or
+ *
+ *   - by linking directly to the core kernel's copy of the global symbol.
+ *
+ * The latter is preferred because it makes the EFIFB earlycon available very
+ * early, but it only works if the EFI stub is part of the core kernel image
+ * itself. The zboot decompressor can only use the configuration table
+ * approach.
+ */
+
+static efi_guid_t primary_display_guid = LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID;
+
+struct sysfb_display_info *__alloc_primary_display(void)
+{
+	struct sysfb_display_info *dpy;
+	efi_status_t status;
+
+	status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY,
+			     sizeof(*dpy), (void **)&dpy);
+
+	if (status != EFI_SUCCESS)
+		return NULL;
+
+	memset(dpy, 0, sizeof(*dpy));
+
+	status = efi_bs_call(install_configuration_table,
+			     &primary_display_guid, dpy);
+	if (status == EFI_SUCCESS)
+		return dpy;
+
+	efi_bs_call(free_pool, dpy);
+	return NULL;
+}
+
+void free_primary_display(struct sysfb_display_info *dpy)
+{
+	if (!dpy)
+		return;
+
+	efi_bs_call(install_configuration_table, &primary_display_guid, NULL);
+	efi_bs_call(free_pool, dpy);
+}
diff --git a/drivers/firmware/efi/libstub/screen_info.c b/drivers/firmware/efi/libstub/screen_info.c
deleted file mode 100644
index 5d3a1e32d177..000000000000
--- a/drivers/firmware/efi/libstub/screen_info.c
+++ /dev/null
@@ -1,53 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <linux/efi.h>
-#include <linux/screen_info.h>
-
-#include <asm/efi.h>
-
-#include "efistub.h"
-
-/*
- * There are two ways of populating the core kernel's struct screen_info via the stub:
- * - using a configuration table, like below, which relies on the EFI init code
- *   to locate the table and copy the contents;
- * - by linking directly to the core kernel's copy of the global symbol.
- *
- * The latter is preferred because it makes the EFIFB earlycon available very
- * early, but it only works if the EFI stub is part of the core kernel image
- * itself. The zboot decompressor can only use the configuration table
- * approach.
- */
-
-static efi_guid_t screen_info_guid = LINUX_EFI_SCREEN_INFO_TABLE_GUID;
-
-struct screen_info *__alloc_screen_info(void)
-{
-	struct screen_info *si;
-	efi_status_t status;
-
-	status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY,
-			     sizeof(*si), (void **)&si);
-
-	if (status != EFI_SUCCESS)
-		return NULL;
-
-	memset(si, 0, sizeof(*si));
-
-	status = efi_bs_call(install_configuration_table,
-			     &screen_info_guid, si);
-	if (status == EFI_SUCCESS)
-		return si;
-
-	efi_bs_call(free_pool, si);
-	return NULL;
-}
-
-void free_screen_info(struct screen_info *si)
-{
-	if (!si)
-		return;
-
-	efi_bs_call(install_configuration_table, &screen_info_guid, NULL);
-	efi_bs_call(free_pool, si);
-}
diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c
index c47ace06f010..4b76f74c56da 100644
--- a/drivers/firmware/efi/libstub/zboot.c
+++ b/drivers/firmware/efi/libstub/zboot.c
@@ -26,9 +26,9 @@ void __weak efi_cache_sync_image(unsigned long image_base,
 	// executable code loaded into memory to be safe for execution.
 }
 
-struct screen_info *alloc_screen_info(void)
+struct sysfb_display_info *alloc_primary_display(void)
 {
-	return __alloc_screen_info();
+	return __alloc_primary_display();
 }
 
 asmlinkage efi_status_t __efiapi
-- 
2.51.1


^ permalink raw reply related

* [PATCH v2 02/10] efi: sysfb_efi: Reduce number of references to global screen_info
From: Thomas Zimmermann @ 2025-11-24 16:40 UTC (permalink / raw)
  To: ardb, javierm, arnd, richard.lyu
  Cc: x86, linux-arm-kernel, linux-kernel, linux-efi, loongarch,
	linux-riscv, dri-devel, linux-hyperv, linux-pci, linux-fbdev,
	Thomas Zimmermann
In-Reply-To: <20251124165116.502813-1-tzimmermann@suse.de>

Replace usage of global screen_info with local pointers. This will
later reduce churn when screen_info is being moved.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Richard Lyu <richard.lyu@suse.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
---
 drivers/firmware/efi/sysfb_efi.c  | 81 ++++++++++++++++---------------
 drivers/firmware/sysfb.c          |  4 +-
 drivers/firmware/sysfb_simplefb.c |  2 +-
 include/linux/sysfb.h             |  9 ++--
 4 files changed, 51 insertions(+), 45 deletions(-)

diff --git a/drivers/firmware/efi/sysfb_efi.c b/drivers/firmware/efi/sysfb_efi.c
index 1e509595ac03..8e0f9d08397f 100644
--- a/drivers/firmware/efi/sysfb_efi.c
+++ b/drivers/firmware/efi/sysfb_efi.c
@@ -92,7 +92,7 @@ void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
 	})
 
 #ifdef CONFIG_EFI
-static int __init efifb_set_system(const struct dmi_system_id *id)
+static int __init efifb_set_system(struct screen_info *si, const struct dmi_system_id *id)
 {
 	struct efifb_dmi_info *info = id->driver_data;
 
@@ -101,14 +101,14 @@ static int __init efifb_set_system(const struct dmi_system_id *id)
 		return 0;
 
 	/* Trust the bootloader over the DMI tables */
-	if (screen_info.lfb_base == 0) {
+	if (si->lfb_base == 0) {
 #if defined(CONFIG_PCI)
 		struct pci_dev *dev = NULL;
 		int found_bar = 0;
 #endif
 		if (info->base) {
-			screen_info.lfb_base = choose_value(info->base,
-				screen_info.lfb_base, OVERRIDE_BASE,
+			si->lfb_base = choose_value(info->base,
+				si->lfb_base, OVERRIDE_BASE,
 				info->flags);
 
 #if defined(CONFIG_PCI)
@@ -135,49 +135,53 @@ static int __init efifb_set_system(const struct dmi_system_id *id)
 
 					start = pci_resource_start(dev, i);
 					end = pci_resource_end(dev, i);
-					if (screen_info.lfb_base >= start &&
-					    screen_info.lfb_base < end) {
+					if (si->lfb_base >= start && si->lfb_base < end) {
 						found_bar = 1;
 						break;
 					}
 				}
 			}
 			if (!found_bar)
-				screen_info.lfb_base = 0;
+				si->lfb_base = 0;
 #endif
 		}
 	}
-	if (screen_info.lfb_base) {
-		screen_info.lfb_linelength = choose_value(info->stride,
-			screen_info.lfb_linelength, OVERRIDE_STRIDE,
+	if (si->lfb_base) {
+		si->lfb_linelength = choose_value(info->stride,
+			si->lfb_linelength, OVERRIDE_STRIDE,
 			info->flags);
-		screen_info.lfb_width = choose_value(info->width,
-			screen_info.lfb_width, OVERRIDE_WIDTH,
+		si->lfb_width = choose_value(info->width,
+			si->lfb_width, OVERRIDE_WIDTH,
 			info->flags);
-		screen_info.lfb_height = choose_value(info->height,
-			screen_info.lfb_height, OVERRIDE_HEIGHT,
+		si->lfb_height = choose_value(info->height,
+			si->lfb_height, OVERRIDE_HEIGHT,
 			info->flags);
-		if (screen_info.orig_video_isVGA == 0)
-			screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
+		if (si->orig_video_isVGA == 0)
+			si->orig_video_isVGA = VIDEO_TYPE_EFI;
 	} else {
-		screen_info.lfb_linelength = 0;
-		screen_info.lfb_width = 0;
-		screen_info.lfb_height = 0;
-		screen_info.orig_video_isVGA = 0;
+		si->lfb_linelength = 0;
+		si->lfb_width = 0;
+		si->lfb_height = 0;
+		si->orig_video_isVGA = 0;
 		return 0;
 	}
 
 	printk(KERN_INFO "efifb: dmi detected %s - framebuffer at 0x%08x "
 			 "(%dx%d, stride %d)\n", id->ident,
-			 screen_info.lfb_base, screen_info.lfb_width,
-			 screen_info.lfb_height, screen_info.lfb_linelength);
+			 si->lfb_base, si->lfb_width,
+			 si->lfb_height, si->lfb_linelength);
 
 	return 1;
 }
 
+static int __init efifb_set_system_callback(const struct dmi_system_id *id)
+{
+	return efifb_set_system(&screen_info, id);
+}
+
 #define EFIFB_DMI_SYSTEM_ID(vendor, name, enumid)		\
 	{							\
-		efifb_set_system,				\
+		efifb_set_system_callback,			\
 		name,						\
 		{						\
 			DMI_MATCH(DMI_BIOS_VENDOR, vendor),	\
@@ -284,12 +288,13 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = {
 	{},
 };
 
-static bool efifb_overlaps_pci_range(const struct of_pci_range *range)
+static bool efifb_overlaps_pci_range(const struct screen_info *si,
+				     const struct of_pci_range *range)
 {
-	u64 fb_base = screen_info.lfb_base;
+	u64 fb_base = si->lfb_base;
 
-	if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
-		fb_base |= (u64)(unsigned long)screen_info.ext_lfb_base << 32;
+	if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE)
+		fb_base |= (u64)(unsigned long)si->ext_lfb_base << 32;
 
 	return fb_base >= range->cpu_addr &&
 	       fb_base < (range->cpu_addr + range->size);
@@ -311,7 +316,7 @@ static struct device_node *find_pci_overlap_node(void)
 		}
 
 		for_each_of_pci_range(&parser, &range)
-			if (efifb_overlaps_pci_range(&range))
+			if (efifb_overlaps_pci_range(&screen_info, &range))
 				return np;
 	}
 	return NULL;
@@ -349,25 +354,25 @@ static const struct fwnode_operations efifb_fwnode_ops = {
 
 static struct fwnode_handle efifb_fwnode;
 
-__init void sysfb_apply_efi_quirks(void)
+__init void sysfb_apply_efi_quirks(struct screen_info *si)
 {
-	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI ||
-	    !(screen_info.capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS))
+	if (si->orig_video_isVGA != VIDEO_TYPE_EFI ||
+	    !(si->capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS))
 		dmi_check_system(efifb_dmi_system_table);
 
-	if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI &&
+	if (si->orig_video_isVGA == VIDEO_TYPE_EFI &&
 	    dmi_check_system(efifb_dmi_swap_width_height)) {
-		u16 temp = screen_info.lfb_width;
+		u16 temp = si->lfb_width;
 
-		screen_info.lfb_width = screen_info.lfb_height;
-		screen_info.lfb_height = temp;
-		screen_info.lfb_linelength = 4 * screen_info.lfb_width;
+		si->lfb_width = si->lfb_height;
+		si->lfb_height = temp;
+		si->lfb_linelength = 4 * si->lfb_width;
 	}
 }
 
-__init void sysfb_set_efifb_fwnode(struct platform_device *pd)
+__init void sysfb_set_efifb_fwnode(const struct screen_info *si, struct platform_device *pd)
 {
-	if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI && IS_ENABLED(CONFIG_PCI)) {
+	if (si->orig_video_isVGA == VIDEO_TYPE_EFI && IS_ENABLED(CONFIG_PCI)) {
 		fwnode_init(&efifb_fwnode, &efifb_fwnode_ops);
 		pd->dev.fwnode = &efifb_fwnode;
 	}
diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c
index 889e5b05c739..916b28538a29 100644
--- a/drivers/firmware/sysfb.c
+++ b/drivers/firmware/sysfb.c
@@ -155,7 +155,7 @@ static __init int sysfb_init(void)
 	if (disabled)
 		goto unlock_mutex;
 
-	sysfb_apply_efi_quirks();
+	sysfb_apply_efi_quirks(si);
 
 	parent = sysfb_parent_dev(si);
 	if (IS_ERR(parent)) {
@@ -200,7 +200,7 @@ static __init int sysfb_init(void)
 
 	pd->dev.parent = parent;
 
-	sysfb_set_efifb_fwnode(pd);
+	sysfb_set_efifb_fwnode(si, pd);
 
 	ret = platform_device_add_data(pd, si, sizeof(*si));
 	if (ret)
diff --git a/drivers/firmware/sysfb_simplefb.c b/drivers/firmware/sysfb_simplefb.c
index 592d8a644619..71f542e37732 100644
--- a/drivers/firmware/sysfb_simplefb.c
+++ b/drivers/firmware/sysfb_simplefb.c
@@ -117,7 +117,7 @@ __init struct platform_device *sysfb_create_simplefb(const struct screen_info *s
 
 	pd->dev.parent = parent;
 
-	sysfb_set_efifb_fwnode(pd);
+	sysfb_set_efifb_fwnode(si, pd);
 
 	ret = platform_device_add_resources(pd, &res, 1);
 	if (ret)
diff --git a/include/linux/sysfb.h b/include/linux/sysfb.h
index b449665c686a..8527a50a5290 100644
--- a/include/linux/sysfb.h
+++ b/include/linux/sysfb.h
@@ -82,16 +82,17 @@ static inline bool sysfb_handles_screen_info(void)
 #ifdef CONFIG_EFI
 
 extern struct efifb_dmi_info efifb_dmi_list[];
-void sysfb_apply_efi_quirks(void);
-void sysfb_set_efifb_fwnode(struct platform_device *pd);
+void sysfb_apply_efi_quirks(struct screen_info *si);
+void sysfb_set_efifb_fwnode(const struct screen_info *si, struct platform_device *pd);
 
 #else /* CONFIG_EFI */
 
-static inline void sysfb_apply_efi_quirks(void)
+static inline void sysfb_apply_efi_quirks(struct screen_info *si)
 {
 }
 
-static inline void sysfb_set_efifb_fwnode(struct platform_device *pd)
+static inline void sysfb_set_efifb_fwnode(const struct screen_info *si,
+					  struct platform_device *pd)
 {
 }
 
-- 
2.51.1


^ permalink raw reply related

* [PATCH v2 03/10] sysfb: Add struct sysfb_display_info
From: Thomas Zimmermann @ 2025-11-24 16:40 UTC (permalink / raw)
  To: ardb, javierm, arnd, richard.lyu
  Cc: x86, linux-arm-kernel, linux-kernel, linux-efi, loongarch,
	linux-riscv, dri-devel, linux-hyperv, linux-pci, linux-fbdev,
	Thomas Zimmermann
In-Reply-To: <20251124165116.502813-1-tzimmermann@suse.de>

Add struct sysfb_display_info to wrap display-related state. For now
it contains only the screen's video mode. Later EDID will be added as
well.

This struct will be helpful for passing display state to sysfb drivers
or from the EFI stub library.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
---
 include/linux/sysfb.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/linux/sysfb.h b/include/linux/sysfb.h
index 8527a50a5290..8b37247528bf 100644
--- a/include/linux/sysfb.h
+++ b/include/linux/sysfb.h
@@ -8,6 +8,7 @@
  */
 
 #include <linux/err.h>
+#include <linux/screen_info.h>
 #include <linux/types.h>
 
 #include <linux/platform_data/simplefb.h>
@@ -60,6 +61,10 @@ struct efifb_dmi_info {
 	int flags;
 };
 
+struct sysfb_display_info {
+	struct screen_info screen;
+};
+
 #ifdef CONFIG_SYSFB
 
 void sysfb_disable(struct device *dev);
-- 
2.51.1


^ permalink raw reply related

* [PATCH v2 01/10] efi: earlycon: Reduce number of references to global screen_info
From: Thomas Zimmermann @ 2025-11-24 16:40 UTC (permalink / raw)
  To: ardb, javierm, arnd, richard.lyu
  Cc: x86, linux-arm-kernel, linux-kernel, linux-efi, loongarch,
	linux-riscv, dri-devel, linux-hyperv, linux-pci, linux-fbdev,
	Thomas Zimmermann
In-Reply-To: <20251124165116.502813-1-tzimmermann@suse.de>

Replace usage of global screen_info with local pointers. This will
later reduce churn when screen_info is being moved.

v2:
- fix coding style

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Richard Lyu <richard.lyu@suse.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
---
 drivers/firmware/efi/earlycon.c | 40 ++++++++++++++++-----------------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/drivers/firmware/efi/earlycon.c b/drivers/firmware/efi/earlycon.c
index d18a1a5de144..42e3a173dac1 100644
--- a/drivers/firmware/efi/earlycon.c
+++ b/drivers/firmware/efi/earlycon.c
@@ -32,12 +32,13 @@ static void *efi_fb;
  */
 static int __init efi_earlycon_remap_fb(void)
 {
+	const struct screen_info *si = &screen_info;
+
 	/* bail if there is no bootconsole or it was unregistered already */
 	if (!earlycon_console || !console_is_registered(earlycon_console))
 		return 0;
 
-	efi_fb = memremap(fb_base, screen_info.lfb_size,
-			  fb_wb ? MEMREMAP_WB : MEMREMAP_WC);
+	efi_fb = memremap(fb_base, si->lfb_size, fb_wb ? MEMREMAP_WB : MEMREMAP_WC);
 
 	return efi_fb ? 0 : -ENOMEM;
 }
@@ -71,12 +72,12 @@ static __ref void efi_earlycon_unmap(void *addr, unsigned long len)
 	early_memunmap(addr, len);
 }
 
-static void efi_earlycon_clear_scanline(unsigned int y)
+static void efi_earlycon_clear_scanline(unsigned int y, const struct screen_info *si)
 {
 	unsigned long *dst;
 	u16 len;
 
-	len = screen_info.lfb_linelength;
+	len = si->lfb_linelength;
 	dst = efi_earlycon_map(y*len, len);
 	if (!dst)
 		return;
@@ -85,7 +86,7 @@ static void efi_earlycon_clear_scanline(unsigned int y)
 	efi_earlycon_unmap(dst, len);
 }
 
-static void efi_earlycon_scroll_up(void)
+static void efi_earlycon_scroll_up(const struct screen_info *si)
 {
 	unsigned long *dst, *src;
 	u16 maxlen = 0;
@@ -99,8 +100,8 @@ static void efi_earlycon_scroll_up(void)
 	}
 	maxlen *= 4;
 
-	len = screen_info.lfb_linelength;
-	height = screen_info.lfb_height;
+	len = si->lfb_linelength;
+	height = si->lfb_height;
 
 	for (i = 0; i < height - font->height; i++) {
 		dst = efi_earlycon_map(i*len, len);
@@ -120,7 +121,8 @@ static void efi_earlycon_scroll_up(void)
 	}
 }
 
-static void efi_earlycon_write_char(u32 *dst, unsigned char c, unsigned int h)
+static void efi_earlycon_write_char(u32 *dst, unsigned char c, unsigned int h,
+				    const struct screen_info *si)
 {
 	const u32 color_black = 0x00000000;
 	const u32 color_white = 0x00ffffff;
@@ -145,13 +147,12 @@ static void efi_earlycon_write_char(u32 *dst, unsigned char c, unsigned int h)
 static void
 efi_earlycon_write(struct console *con, const char *str, unsigned int num)
 {
-	struct screen_info *si;
+	const struct screen_info *si = &screen_info;
 	u32 cur_efi_x = efi_x;
 	unsigned int len;
 	const char *s;
 	void *dst;
 
-	si = &screen_info;
 	len = si->lfb_linelength;
 
 	while (num) {
@@ -174,7 +175,7 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num)
 			x = efi_x;
 
 			while (n-- > 0) {
-				efi_earlycon_write_char(dst + x*4, *s, h);
+				efi_earlycon_write_char(dst + x * 4, *s, h, si);
 				x += font->width;
 				s++;
 			}
@@ -207,10 +208,10 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num)
 			cur_line_y = (cur_line_y + 1) % max_line_y;
 
 			efi_y -= font->height;
-			efi_earlycon_scroll_up();
+			efi_earlycon_scroll_up(si);
 
 			for (i = 0; i < font->height; i++)
-				efi_earlycon_clear_scanline(efi_y + i);
+				efi_earlycon_clear_scanline(efi_y + i, si);
 		}
 	}
 }
@@ -226,22 +227,21 @@ void __init efi_earlycon_reprobe(void)
 static int __init efi_earlycon_setup(struct earlycon_device *device,
 				     const char *opt)
 {
-	struct screen_info *si;
+	const struct screen_info *si = &screen_info;
 	u16 xres, yres;
 	u32 i;
 
 	fb_wb = opt && !strcmp(opt, "ram");
 
-	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) {
+	if (si->orig_video_isVGA != VIDEO_TYPE_EFI) {
 		fb_probed = true;
 		return -ENODEV;
 	}
 
-	fb_base = screen_info.lfb_base;
-	if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
-		fb_base |= (u64)screen_info.ext_lfb_base << 32;
+	fb_base = si->lfb_base;
+	if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE)
+		fb_base |= (u64)si->ext_lfb_base << 32;
 
-	si = &screen_info;
 	xres = si->lfb_width;
 	yres = si->lfb_height;
 
@@ -266,7 +266,7 @@ static int __init efi_earlycon_setup(struct earlycon_device *device,
 
 	efi_y -= font->height;
 	for (i = 0; i < (yres - efi_y) / font->height; i++)
-		efi_earlycon_scroll_up();
+		efi_earlycon_scroll_up(si);
 
 	device->con->write = efi_earlycon_write;
 	earlycon_console = device->con;
-- 
2.51.1


^ permalink raw reply related

* [PATCH v2 00/10] arch,sysfb,efi: Support EDID on non-x86 EFI systems
From: Thomas Zimmermann @ 2025-11-24 16:40 UTC (permalink / raw)
  To: ardb, javierm, arnd, richard.lyu
  Cc: x86, linux-arm-kernel, linux-kernel, linux-efi, loongarch,
	linux-riscv, dri-devel, linux-hyperv, linux-pci, linux-fbdev,
	Thomas Zimmermann

Replace screen_info and edid_info with sysfb_primary_device of type
struct sysfb_display_info. Update all users. Then implement EDID support
in EFI's libstub.

Sysfb DRM drivers currently fetch the global edid_info directly, when
they should get that information together with the screen_info from their
device. Wrapping screen_info and edid_info in sysfb_primary_display and
passing this to drivers enables this.

Replacing both with sysfb_primary_display has been motivate by the EFI
stub. EFI wants to transfer EDID via config table in a single entry.
Using struct sysfb_display_info this will become easily possible. Hence
accept some churn in architecture code for the long-term improvements.

Add a new UUID to transfer sysfb_primary_display via EFI's config table.
Then implement support in the kernel and EFI's libstub.

Patches 1 and 2 reduce the exposure of screen_info in EFI-related code.

Patch 3 adds struct sysfb_display_info.

Patch 4 replaces scren_info with sysfb_primary_display. This results in
several changes throught the kernel, but is really just a refactoring.

Patch 5 updates sysfb to transfer sysfb_primary_display to the related
drivers.

Patch 6 moves edid_info into sysfb_primary_display. This resolves some
drivers' reference to the global edid_info, but also makes the EDID data
available on non-x86 architectures.

Patches 7 and 8 add kernel-side support for EDID transfers on non-x86
EFI systems.

Patches 9 implements EDID support in libstub. Patch 10 cleans up the
config-table allocation to be easier to understand.

This is v2 of the series. It combines v1 of the series at [1] plus
changes from [2] and [3].

[1] https://lore.kernel.org/dri-devel/20251121135624.494768-1-tzimmermann@suse.de/
[2] https://lore.kernel.org/dri-devel/20251015160816.525825-1-tzimmermann@suse.de/
[3] https://lore.kernel.org/linux-efi/20251119123011.1187249-5-ardb+git@google.com/

Thomas Zimmermann (10):
  efi: earlycon: Reduce number of references to global screen_info
  efi: sysfb_efi: Reduce number of references to global screen_info
  sysfb: Add struct sysfb_display_info
  sysfb: Replace screen_info with sysfb_primary_display
  sysfb: Pass sysfb_primary_display to devices
  sysfb: Move edid_info into sysfb_primary_display
  efi: Refactor init_primary_display() helpers
  efi: Support EDID information
  efi: libstub: Transfer EDID to kernel
  efi: libstub: Simplify interfaces for primary_display

 arch/arm64/kernel/image-vars.h                |  2 +-
 arch/loongarch/kernel/efi.c                   | 47 +++++++----
 arch/loongarch/kernel/image-vars.h            |  2 +-
 arch/riscv/kernel/image-vars.h                |  2 +-
 arch/x86/kernel/kexec-bzimage64.c             |  4 +-
 arch/x86/kernel/setup.c                       | 16 ++--
 arch/x86/video/video-common.c                 |  4 +-
 drivers/firmware/efi/earlycon.c               | 42 +++++-----
 drivers/firmware/efi/efi-init.c               | 47 +++++++----
 drivers/firmware/efi/efi.c                    |  2 +
 drivers/firmware/efi/libstub/Makefile         |  2 +-
 drivers/firmware/efi/libstub/efi-stub-entry.c | 36 +++++++--
 drivers/firmware/efi/libstub/efi-stub.c       | 49 +++++++----
 drivers/firmware/efi/libstub/efistub.h        |  7 +-
 .../firmware/efi/libstub/primary_display.c    | 41 ++++++++++
 drivers/firmware/efi/libstub/screen_info.c    | 53 ------------
 drivers/firmware/efi/libstub/zboot.c          |  6 +-
 drivers/firmware/efi/sysfb_efi.c              | 81 ++++++++++---------
 drivers/firmware/sysfb.c                      | 13 +--
 drivers/firmware/sysfb_simplefb.c             |  2 +-
 drivers/gpu/drm/sysfb/efidrm.c                | 14 ++--
 drivers/gpu/drm/sysfb/vesadrm.c               | 14 ++--
 drivers/hv/vmbus_drv.c                        |  6 +-
 drivers/pci/vgaarb.c                          |  4 +-
 drivers/video/Kconfig                         |  8 +-
 drivers/video/fbdev/core/fbmon.c              |  8 +-
 drivers/video/fbdev/efifb.c                   | 10 ++-
 drivers/video/fbdev/vesafb.c                  | 10 ++-
 drivers/video/fbdev/vga16fb.c                 |  8 +-
 drivers/video/screen_info_pci.c               |  5 +-
 include/linux/efi.h                           |  8 +-
 include/linux/screen_info.h                   |  2 -
 include/linux/sysfb.h                         | 23 ++++--
 include/video/edid.h                          |  4 -
 34 files changed, 337 insertions(+), 245 deletions(-)
 create mode 100644 drivers/firmware/efi/libstub/primary_display.c
 delete mode 100644 drivers/firmware/efi/libstub/screen_info.c


base-commit: d724c6f85e80a23ed46b7ebc6e38b527c09d64f5
-- 
2.51.1


^ permalink raw reply


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