mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-09-22 09:34:56 +02:00
LoongArch: Add PIO for early access before ACPI PCI root register
commit 6061e65f95 upstream.
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>
Tested-by: Yuanzhen Gan <elysia-best@simplelinux.cn.eu.org>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
86df6499df
commit
30d5d4eef3
@@ -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);
|
||||
|
||||
static inline u32 get_acpi_id_for_cpu(unsigned int cpu)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -510,6 +510,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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user