mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] LoongArch: Add PIO for early access before ACPI PCI root register
@ 2026-06-22  6:58 Huacai Chen
  2026-06-24 16:15 ` Yuanzhen Gan
  0 siblings, 1 reply; 2+ messages in thread
From: Huacai Chen @ 2026-06-22  6:58 UTC (permalink / raw)
  To: Huacai Chen
  Cc: loongarch, Xuefeng Li, Guo Ren, Xuerui Wang, Jiaxun Yang,
	linux-kernel, Huacai Chen, stable

For ACPI system we suppose the ISA/LPC PIO range is registered together
with PCI root bridge. But the fact is there may be some early access to
the ISA/LPC PIO range before ACPI PCI root register (most of them are
due to abnormal BIOS). Unconditionally register the ISA/LPC PIO range
usually causes ACPI PCI root register fail because of the address range
confliction. So we add a pair of helpers: acpi_add_early_pio() to add
PIO for early access, and acpi_remove_early_pio() to remove PIO before
PCI root register. Since acpi_remove_early_pio() may be called multiple
times, we add an acpi_pio flag to ensure PIO be removed only once.

Cc: <stable@vger.kernel.org>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
---
 arch/loongarch/include/asm/acpi.h |  2 ++
 arch/loongarch/kernel/acpi.c      | 28 ++++++++++++++++++++++++++++
 arch/loongarch/kernel/setup.c     |  2 ++
 arch/loongarch/pci/acpi.c         |  2 ++
 4 files changed, 34 insertions(+)

diff --git a/arch/loongarch/include/asm/acpi.h b/arch/loongarch/include/asm/acpi.h
index eda9d4d0a493..c05168aedcaa 100644
--- a/arch/loongarch/include/asm/acpi.h
+++ b/arch/loongarch/include/asm/acpi.h
@@ -38,6 +38,8 @@ static inline bool acpi_has_cpu_in_madt(void)
 extern struct list_head acpi_wakeup_device_list;
 extern struct acpi_madt_core_pic acpi_core_pic[MAX_CORE_PIC];
 
+extern void acpi_add_early_pio(void);
+extern void acpi_remove_early_pio(void);
 extern int __init parse_acpi_topology(void);
 
 #endif /* !CONFIG_ACPI */
diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c
index 058f0dbe8e8f..8f650c9ffecd 100644
--- a/arch/loongarch/kernel/acpi.c
+++ b/arch/loongarch/kernel/acpi.c
@@ -16,6 +16,7 @@
 #include <linux/memblock.h>
 #include <linux/of_fdt.h>
 #include <linux/serial_core.h>
+#include <linux/vmalloc.h>
 #include <asm/io.h>
 #include <asm/numa.h>
 #include <asm/loongson.h>
@@ -59,6 +60,33 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
 		return ioremap_cache(phys, size);
 }
 
+#define PIO_BASE (unsigned long)PCI_IOBASE
+#define PIO_SIZE ALIGN(ISA_IOSIZE, PAGE_SIZE)
+
+static bool acpi_pio;
+
+/* Add PIO for early access */
+void acpi_add_early_pio(void)
+{
+	if (!acpi_disabled) {
+		acpi_pio = true;
+		vmap_page_range(PIO_BASE, PIO_BASE + PIO_SIZE,
+				LOONGSON_LIO_BASE, pgprot_device(PAGE_KERNEL));
+	}
+}
+
+/* Remove PIO for PCI register */
+void acpi_remove_early_pio(void)
+{
+	if (!acpi_pio)
+		return;
+
+	if (!acpi_disabled) {
+		acpi_pio = false;
+		vunmap_range(PIO_BASE, PIO_BASE + PIO_SIZE);
+	}
+}
+
 #ifdef CONFIG_SMP
 static int set_processor_mask(u32 id, u32 pass)
 {
diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
index 369262117c63..eaebb52bd36e 100644
--- a/arch/loongarch/kernel/setup.c
+++ b/arch/loongarch/kernel/setup.c
@@ -502,6 +502,8 @@ static __init int arch_reserve_pio_range(void)
 {
 	struct device_node *np;
 
+	acpi_add_early_pio();
+
 	for_each_node_by_name(np, "isa") {
 		struct of_range range;
 		struct of_range_parser parser;
diff --git a/arch/loongarch/pci/acpi.c b/arch/loongarch/pci/acpi.c
index b02698a338ee..ccbcea61fcd9 100644
--- a/arch/loongarch/pci/acpi.c
+++ b/arch/loongarch/pci/acpi.c
@@ -65,6 +65,8 @@ static int acpi_prepare_root_resources(struct acpi_pci_root_info *ci)
 	struct resource_entry *entry, *tmp;
 	struct acpi_device *device = ci->bridge;
 
+	acpi_remove_early_pio();
+
 	status = acpi_pci_probe_root_resources(ci);
 	if (status > 0) {
 		acpi_evaluate_integer(device->handle, "PCIH", NULL, &pci_h);
-- 
2.52.0


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] LoongArch: Add PIO for early access before ACPI PCI root register
  2026-06-22  6:58 [PATCH] LoongArch: Add PIO for early access before ACPI PCI root register Huacai Chen
@ 2026-06-24 16:15 ` Yuanzhen Gan
  0 siblings, 0 replies; 2+ messages in thread
From: Yuanzhen Gan @ 2026-06-24 16:15 UTC (permalink / raw)
  To: Huacai Chen, Huacai Chen
  Cc: loongarch, Xuefeng Li, Guo Ren, Xuerui Wang, Jiaxun Yang,
	linux-kernel, stable, Kexy Biscuit, Mingcong Bai

On Mon, 22 Jun 2026 14:58:43 +0800, Huacai Chen <chenhuacai@loongson.cn> 
wrote:
  > For ACPI system we suppose the ISA/LPC PIO range is registered together
  > with PCI root bridge. But the fact is there may be some early access to
  > the ISA/LPC PIO range before ACPI PCI root register (most of them are
  > due to abnormal BIOS). Unconditionally register the ISA/LPC PIO range
  > usually causes ACPI PCI root register fail because of the address range
  > confliction. So we add a pair of helpers: acpi_add_early_pio() to add
  > PIO for early access, and acpi_remove_early_pio() to remove PIO before
  > PCI root register. Since acpi_remove_early_pio() may be called multiple
  > times, we add an acpi_pio flag to ensure PIO be removed only once.
  >
  > Cc: <stable@vger.kernel.org>
  > Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
  > ---
  >  arch/loongarch/include/asm/acpi.h |  2 ++
  >  arch/loongarch/kernel/acpi.c      | 28 ++++++++++++++++++++++++++++
  >  arch/loongarch/kernel/setup.c     |  2 ++
  >  arch/loongarch/pci/acpi.c         |  2 ++
  >  4 files changed, 34 insertions(+)
  >
  > diff --git a/arch/loongarch/include/asm/acpi.h 
b/arch/loongarch/include/asm/acpi.h
  > index eda9d4d0a493..c05168aedcaa 100644
  > --- a/arch/loongarch/include/asm/acpi.h
  > +++ b/arch/loongarch/include/asm/acpi.h
  > @@ -38,6 +38,8 @@ static inline bool acpi_has_cpu_in_madt(void)
  >  extern struct list_head acpi_wakeup_device_list;
  >  extern struct acpi_madt_core_pic acpi_core_pic[MAX_CORE_PIC];
  >
  > +extern void acpi_add_early_pio(void);
  > +extern void acpi_remove_early_pio(void);
  >  extern int __init parse_acpi_topology(void);
  >
  >  #endif /* !CONFIG_ACPI */
  > diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c
  > index 058f0dbe8e8f..8f650c9ffecd 100644
  > --- a/arch/loongarch/kernel/acpi.c
  > +++ b/arch/loongarch/kernel/acpi.c
  > @@ -16,6 +16,7 @@
  >  #include <linux/memblock.h>
  >  #include <linux/of_fdt.h>
  >  #include <linux/serial_core.h>
  > +#include <linux/vmalloc.h>
  >  #include <asm/io.h>
  >  #include <asm/numa.h>
  >  #include <asm/loongson.h>
  > @@ -59,6 +60,33 @@ void __iomem 
*acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
  >  		return ioremap_cache(phys, size);
  >  }
  >
  > +#define PIO_BASE (unsigned long)PCI_IOBASE
  > +#define PIO_SIZE ALIGN(ISA_IOSIZE, PAGE_SIZE)
  > +
  > +static bool acpi_pio;
  > +
  > +/* Add PIO for early access */
  > +void acpi_add_early_pio(void)
  > +{
  > +	if (!acpi_disabled) {
  > +		acpi_pio = true;
  > +		vmap_page_range(PIO_BASE, PIO_BASE + PIO_SIZE,
  > +				LOONGSON_LIO_BASE, pgprot_device(PAGE_KERNEL));
  > +	}
  > +}
  > +
  > +/* Remove PIO for PCI register */
  > +void acpi_remove_early_pio(void)
  > +{
  > +	if (!acpi_pio)
  > +		return;
  > +
  > +	if (!acpi_disabled) {
  > +		acpi_pio = false;
  > +		vunmap_range(PIO_BASE, PIO_BASE + PIO_SIZE);
  > +	}
  > +}
  > +
  >  #ifdef CONFIG_SMP
  >  static int set_processor_mask(u32 id, u32 pass)
  >  {
  > diff --git a/arch/loongarch/kernel/setup.c 
b/arch/loongarch/kernel/setup.c
  > index 369262117c63..eaebb52bd36e 100644
  > --- a/arch/loongarch/kernel/setup.c
  > +++ b/arch/loongarch/kernel/setup.c
  > @@ -502,6 +502,8 @@ static __init int arch_reserve_pio_range(void)
  >  {
  >  	struct device_node *np;
  >
  > +	acpi_add_early_pio();
  > +
  >  	for_each_node_by_name(np, "isa") {
  >  		struct of_range range;
  >  		struct of_range_parser parser;
  > diff --git a/arch/loongarch/pci/acpi.c b/arch/loongarch/pci/acpi.c
  > index b02698a338ee..ccbcea61fcd9 100644
  > --- a/arch/loongarch/pci/acpi.c
  > +++ b/arch/loongarch/pci/acpi.c
  > @@ -65,6 +65,8 @@ static int acpi_prepare_root_resources(struct 
acpi_pci_root_info *ci)
  >  	struct resource_entry *entry, *tmp;
  >  	struct acpi_device *device = ci->bridge;
  >
  > +	acpi_remove_early_pio();
  > +
  >  	status = acpi_pci_probe_root_resources(ci);
  >  	if (status > 0) {
  >  		acpi_evaluate_integer(device->handle, "PCIH", NULL, &pci_h);

I have tested this patch on my Loongson-3A6000 system with Kunlun 
firmware. The patch successfully resolves the ACPI PCI root bridge 
registration issue caused by early ISA/LPC PIO access.

On this platform, the DSDT defines _CRS methods for UAR and LPT devices 
that call the ENFG() and EXFG() methods from the ITE1 device. This 
causes early writes to the ISA/LPC PIO range before PCI root bridge 
registration. The patch's early PIO registration mechanism properly 
handles this firmware quirk.

Test environment:
- Platform: Seewo OEM 3A6000 (CB,L3A6.MA01 V1.0)
- Firmware: Kunlun BIOS
- CPU: Loongson-3A6000-HV @ 2.50 GHz
- OS: AOSC OS 13.2.0 (loongarch64)
- Kernel: Linux 7.0.13-aosc-main-16k

The system boots successfully when the patch is applied.

Cc: Mingcong Bai <jeffbai@aosc.io>
Cc: Kexy Biscuit <kexybiscuit@aosc.io>
Tested-by: Yuanzhen Gan <elysia-best@simplelinux.cn.eu.org>


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-06-24 16:51 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-22  6:58 [PATCH] LoongArch: Add PIO for early access before ACPI PCI root register Huacai Chen
2026-06-24 16:15 ` Yuanzhen Gan

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

all inboxes | Powered by JetHome®