Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save shankerwangmiao/a15e17fc5c1c1dfb883490862107fcbb to your computer and use it in GitHub Desktop.
Save shankerwangmiao/a15e17fc5c1c1dfb883490862107fcbb to your computer and use it in GitHub Desktop.
From 75fc6f7e57c2677025b2bc271f3c18825140f21e Mon Sep 17 00:00:00 2001
From: Miao Wang <[email protected]>
Date: Wed, 17 Jul 2024 09:03:32 +0800
Subject: [PATCH 01/11] loongarch: basic boot support for legacy firmware
The addresses passed from legacy firmware in efi system tables, the
initrd table, the efi system memory mapping table are virtual addresses.
This patch converts all that addresses back to physical addresses, to
make sure all the following booting processes can run smoothly like on
modern firmwares. The conversion happens unconditionally, since physical
addresses passed in by modern firmwares remain unchanged after the
conversion.
In the EFI Stub, the mapping entries given by GetMemoryMap() on legacy
firmwares contain virtual addresses in the phys_addr fields and 0x1xxxx
addresses in the virt_addr fields, causing the later call to
SetVirtualAddressMap() fails. This patch fixes this by correcting the
addresses in the virt_addr fields. This patch detects the existence of
the legacy firmware by reading DMW1 CSR, as done in the legacy loongarch
GRUB port. Only if legacy firmwares detected, this correction happens.
With this patch, the linux kernel is basically able to boot.
---
arch/loongarch/kernel/efi.c | 18 ++++++++++++++++++
arch/loongarch/kernel/mem.c | 1 +
drivers/firmware/efi/libstub/loongarch.c | 18 ++++++++++++++++++
3 files changed, 37 insertions(+)
diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c
index 000825406c1f..304afd6c2fd9 100644
--- a/arch/loongarch/kernel/efi.c
+++ b/arch/loongarch/kernel/efi.c
@@ -92,6 +92,23 @@ static void __init init_screen_info(void)
memblock_reserve(screen_info.lfb_base, screen_info.lfb_size);
}
+static void __init fix_initrd_table(const efi_config_table_t *config_tables,
+ int count)
+{
+ for(int i = 0; i < count; i++) {
+ if (efi_guidcmp(config_tables[i].guid,
+ LINUX_EFI_INITRD_MEDIA_GUID) == 0) {
+ struct linux_efi_initrd *tbl =
+ early_memremap((u64)config_tables[i].table, sizeof(*tbl));
+ if (tbl) {
+ tbl->base = TO_PHYS(tbl->base);
+ early_memunmap(tbl, sizeof(*tbl));
+ }
+ break;
+ }
+ }
+}
+
void __init efi_init(void)
{
int size;
@@ -115,6 +132,7 @@ void __init efi_init(void)
size = sizeof(efi_config_table_t);
config_tables = early_memremap(efi_config_table, efi_nr_tables * size);
+ fix_initrd_table(config_tables, efi_systab->nr_tables);
efi_config_parse_tables(config_tables, efi_systab->nr_tables, arch_tables);
early_memunmap(config_tables, efi_nr_tables * size);
diff --git a/arch/loongarch/kernel/mem.c b/arch/loongarch/kernel/mem.c
index aed901c57fb4..86d37a447eec 100644
--- a/arch/loongarch/kernel/mem.c
+++ b/arch/loongarch/kernel/mem.c
@@ -19,6 +19,7 @@ void __init memblock_init(void)
/* Parse memory information */
for_each_efi_memory_desc(md) {
mem_type = md->type;
+ md->phys_addr = TO_PHYS(md->phys_addr);
mem_start = md->phys_addr;
mem_size = md->num_pages << EFI_PAGE_SHIFT;
mem_end = mem_start + mem_size;
diff --git a/drivers/firmware/efi/libstub/loongarch.c b/drivers/firmware/efi/libstub/loongarch.c
index d0ef93551c44..e0ae9c8550c3 100644
--- a/drivers/firmware/efi/libstub/loongarch.c
+++ b/drivers/firmware/efi/libstub/loongarch.c
@@ -23,6 +23,8 @@ struct exit_boot_struct {
int runtime_entry_count;
};
+static int is_oldworld = 0;
+
static efi_status_t exit_boot_func(struct efi_boot_memmap *map, void *priv)
{
struct exit_boot_struct *p = priv;
@@ -38,6 +40,15 @@ static efi_status_t exit_boot_func(struct efi_boot_memmap *map, void *priv)
return EFI_SUCCESS;
}
+static void detect_oldworld(void)
+{
+ is_oldworld = !!(csr_read64(LOONGARCH_CSR_DMWIN1) & CSR_DMW1_PLV0);
+ efi_debug("is_oldworld: %d\n", is_oldworld);
+ if(is_oldworld) {
+ efi_info("Booting on OldWorld firmware\n");
+ }
+}
+
unsigned long __weak kernel_entry_address(unsigned long kernel_addr,
efi_loaded_image_t *image)
{
@@ -53,6 +64,8 @@ efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image,
efi_status_t status;
u32 desc_ver;
+ detect_oldworld();
+
status = efi_alloc_virtmap(&priv.runtime_map, &desc_size, &desc_ver);
if (status != EFI_SUCCESS) {
efi_err("Unable to retrieve UEFI memory map.\n");
@@ -66,11 +79,16 @@ efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image,
if (status != EFI_SUCCESS)
return status;
+ if (is_oldworld) {
+ goto skip_set_virtual_address_map;
+ }
+
/* Install the new virtual address map */
efi_rt_call(set_virtual_address_map,
priv.runtime_entry_count * desc_size, desc_size,
desc_ver, priv.runtime_map);
+skip_set_virtual_address_map:
/* Config Direct Mapping */
csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0);
csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1);
--
2.43.0
From e0c4df5c8e96295ca7b8767b10ed48b45f9d75f5 Mon Sep 17 00:00:00 2001
From: Miao Wang <[email protected]>
Date: Wed, 17 Jul 2024 09:16:26 +0800
Subject: [PATCH] loongarch64: able to start on legacy firmware
On legacy firmware, the DMW is already enabled by the firmware, and the
addresses in all the pointers and the PC register are virtual addresses.
GRUB, however, is location independent, so will not be affected. The
only problem happens at the GRUB_EFI_MAX_USABLE_ADDRESS, which should
be dynamically decided by detecting if DMW is enabled.
---
include/grub/loongarch64/efi/memory.h | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/include/grub/loongarch64/efi/memory.h b/include/grub/loongarch64/efi/memory.h
index d460267be..534ba4b32 100644
--- a/include/grub/loongarch64/efi/memory.h
+++ b/include/grub/loongarch64/efi/memory.h
@@ -19,6 +19,25 @@
#ifndef GRUB_MEMORY_CPU_HEADER
#include <grub/efi/memory.h>
-#define GRUB_EFI_MAX_USABLE_ADDRESS 0xfffffffffffULL
+static inline grub_uint64_t
+grub_efi_max_usable_address(void)
+{
+ static grub_uint64_t addr;
+ static int addr_valid = 0;
+
+ if (!addr_valid)
+ {
+ asm volatile ("csrrd %0, 0x181" : "=r" (addr));
+ if (addr & 0x1)
+ addr |= 0xfffffffffffUL;
+ else
+ addr = 0xfffffffffffUL;
+ addr_valid = 1;
+ }
+
+ return addr;
+}
+
+#define GRUB_EFI_MAX_USABLE_ADDRESS (grub_efi_max_usable_address())
#endif /* ! GRUB_MEMORY_CPU_HEADER */
--
2.42.0
From 0d8ec4a8138a4da66746aa2419f81f1895f34780 Mon Sep 17 00:00:00 2001
From: Miao Wang <[email protected]>
Date: Thu, 18 Jul 2024 18:55:59 +0800
Subject: [PATCH 02/11] loongarch: parse BPI data and add memory mapping
On legacy firmwares, the memory mapping information passed in the EFI
system table is not enough to cover all the available memory regions,
but only contains the memory region which occupied by the firmware, with
the total size of ~1GiB. More information is stored in the BPI data
structure. The complete information is combined into from the both
sources.
This patch addes the mechanism to parse the BPI data structure and
extract the memory mapping information from it. This patch also adds the
memory regions defined in the BPI to the kernel, letting the kernel to
discover all the available memory regions.
With this patch, machines with legacy firmware, with the BPI version
BPI01001, i.e. the newer version, can boot normally.
---
arch/loongarch/kernel/Makefile | 2 +
arch/loongarch/kernel/efi.c | 3 +
arch/loongarch/kernel/legacy_boot.c | 297 ++++++++++++++++++++++++++++
arch/loongarch/kernel/legacy_boot.h | 18 ++
arch/loongarch/kernel/mem.c | 4 +
arch/loongarch/kernel/numa.c | 3 +
arch/loongarch/kernel/setup.c | 3 +
arch/loongarch/kernel/smp.c | 4 +
8 files changed, 334 insertions(+)
create mode 100644 arch/loongarch/kernel/legacy_boot.c
create mode 100644 arch/loongarch/kernel/legacy_boot.h
diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
index 3a7620b66bc6..84d2e2d896ab 100644
--- a/arch/loongarch/kernel/Makefile
+++ b/arch/loongarch/kernel/Makefile
@@ -78,3 +78,5 @@ obj-$(CONFIG_UPROBES) += uprobes.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS)
+
+obj-y += legacy_boot.o
diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c
index 304afd6c2fd9..307f35d1e71f 100644
--- a/arch/loongarch/kernel/efi.c
+++ b/arch/loongarch/kernel/efi.c
@@ -25,6 +25,8 @@
#include <asm/efi.h>
#include <asm/loongson.h>
+#include "legacy_boot.h"
+
static unsigned long efi_nr_tables;
static unsigned long efi_config_table;
@@ -35,6 +37,7 @@ static efi_system_table_t *efi_systab;
static efi_config_table_type_t arch_tables[] __initdata = {
{LINUX_EFI_BOOT_MEMMAP_GUID, &boot_memmap, "MEMMAP" },
{DEVICE_TREE_GUID, &fdt_pointer, "FDTPTR" },
+ {LOONGARCH_BPI_GUID, &loongarch_bpi_info.bpi, "BPI" },
{},
};
diff --git a/arch/loongarch/kernel/legacy_boot.c b/arch/loongarch/kernel/legacy_boot.c
new file mode 100644
index 000000000000..30c01c8b22a0
--- /dev/null
+++ b/arch/loongarch/kernel/legacy_boot.c
@@ -0,0 +1,297 @@
+#include <linux/efi.h>
+#include <linux/memblock.h>
+
+#include <asm/early_ioremap.h>
+
+#include "legacy_boot.h"
+
+#define LOONGARCH_BOOT_MEM_MAP_MAX 128
+
+enum bpi_vers {
+ BPI_VERSION_NONE = 0,
+ BPI_VERSION_V1 = 1000,
+ BPI_VERSION_V2 = 1001,
+};
+
+struct loongarch_bpi_ext_hdr {
+ u64 signature;
+ u32 length;
+ u8 revision;
+ u8 checksum;
+ u64 next;
+} __packed;
+
+struct loongarch_bpi_hdr {
+ u64 signature;
+ u64 systemtable;
+ u64 extlist;
+ u64 flags;
+} __packed;
+
+enum bpi_mem_type {
+ ADDRESS_TYPE_SYSRAM = 1,
+ ADDRESS_TYPE_RESERVED = 2,
+ ADDRESS_TYPE_ACPI = 3,
+ ADDRESS_TYPE_NVS = 4,
+ ADDRESS_TYPE_PMEM = 5,
+ ADDRESS_TYPE_MAX,
+};
+
+struct loongarch_bpi_mem_map {
+ struct loongarch_bpi_ext_hdr header; /*{"M", "E", "M"}*/
+ u8 map_count;
+ struct loongarch_bpi_mem_map_entry {
+ u32 mem_type;
+ u64 mem_start;
+ u64 mem_size;
+ } __packed map[];
+} __packed;
+
+struct loongarch_bpi_info __initdata loongarch_bpi_info = {
+ .bpi = EFI_INVALID_TABLE_ADDR,
+};
+
+static enum bpi_vers __initdata bpi_version = BPI_VERSION_NONE;
+static u64 __initdata bpi_flags = 0;
+
+static int have_bpi = 0;
+
+static __initdata struct {
+ size_t map_count;
+ struct loongarch_bpi_memmap{
+ enum bpi_mem_type type;
+ unsigned long mem_start;
+ size_t mem_size;
+ } map[LOONGARCH_BOOT_MEM_MAP_MAX];
+} bpi_meminfo = {0};
+
+static __initdata struct {
+ unsigned long addr;
+ size_t size;
+} bpi_memmap = {
+ .addr = EFI_INVALID_TABLE_ADDR,
+ .size = 0,
+};
+
+static const __initconst struct bpi_extlist_desc {
+ union {
+ u64 signature;
+ char chars[8];
+ };
+ unsigned long *ptr;
+ size_t *length;
+} bpi_extlist[] = {
+ { .chars = "MEM", &bpi_memmap.addr, &bpi_memmap.size },
+ { .signature = 0, NULL, NULL },
+};
+
+
+static void __init parse_bpi_ext_list(unsigned long exthdr)
+{
+ unsigned long cur_hdr = exthdr;
+ while(cur_hdr){
+ struct loongarch_bpi_ext_hdr *hdr = early_memremap_ro(cur_hdr, sizeof(*hdr));
+ if(!hdr) {
+ break;
+ }
+ u64 sig = hdr->signature;
+ u32 len = hdr->length;
+ u8 rev = hdr->revision;
+ unsigned long next = hdr->next;
+ early_memunmap(hdr, sizeof(*hdr));
+
+ pr_info("BPI: ext hdr: %.8s, rev %u\n", (const char *)&sig, rev);
+
+ for(const struct bpi_extlist_desc *desc = bpi_extlist; desc->signature; desc++) {
+ if(sig == desc->signature) {
+ *(desc->ptr) = cur_hdr;
+ *(desc->length) = len;
+ }
+ }
+ cur_hdr = next;
+ }
+}
+
+
+static u8 __init ext_listhdr_checksum(void *buffer, size_t length)
+{
+ u8 sum = 0;
+ u8 *end = buffer + length;
+ u8 *buf = buffer;
+
+ while (buf < end)
+ sum = (u8)(sum + *(buf++));
+
+ return sum;
+}
+
+static void __init parse_bpi_mem_map(void)
+{
+ if(bpi_memmap.addr == EFI_INVALID_TABLE_ADDR) {
+ return;
+ }
+ if(bpi_memmap.size < sizeof(struct loongarch_bpi_mem_map)) {
+ pr_err("BPI: invalid memmap size %ld\n", bpi_memmap.size);
+ return;
+ }
+ struct loongarch_bpi_mem_map *memmap = early_memremap_ro(bpi_memmap.addr, bpi_memmap.size);
+ if(!memmap) {
+ return;
+ }
+
+ u8 checksum = ext_listhdr_checksum(memmap, bpi_memmap.size);
+ if (checksum != 0) {
+ pr_err("BPI: memmap checksum mismatch\n");
+ goto err_out;
+ }
+
+ size_t map_count = memmap->map_count;
+ if (map_count > LOONGARCH_BOOT_MEM_MAP_MAX) {
+ pr_err("BPI: too many memmap entries\n");
+ goto err_out;
+ }
+ if (map_count * sizeof(memmap->map[0]) + sizeof(*memmap) > bpi_memmap.size) {
+ pr_err("BPI: invalid memmap size %ld, not enough to hold %ld entries\n", bpi_memmap.size, map_count);
+ goto err_out;
+ }
+ for(int i = 0; i < map_count; i++) {
+ bpi_meminfo.map[i].type = memmap->map[i].mem_type;
+ bpi_meminfo.map[i].mem_start = memmap->map[i].mem_start;
+ bpi_meminfo.map[i].mem_size = memmap->map[i].mem_size;
+
+ static const char * const __initconst mem_type_str[] = {
+ NULL,
+ [ADDRESS_TYPE_SYSRAM] = "SYSRAM",
+ [ADDRESS_TYPE_RESERVED] = "RESERVED",
+ [ADDRESS_TYPE_ACPI] = "ACPI",
+ [ADDRESS_TYPE_NVS] = "NVS",
+ [ADDRESS_TYPE_PMEM] = "PMEM",
+ };
+ if(bpi_meminfo.map[i].type >= ADDRESS_TYPE_MAX || bpi_meminfo.map[i].type == 0) {
+ pr_info("BPI: memmap type unknown(%d), start 0x%lx, size 0x%lx\n", bpi_meminfo.map[i].type, bpi_meminfo.map[i].mem_start, bpi_meminfo.map[i].mem_size);
+ }else{
+ pr_info("BPI: memmap type %s, start 0x%lx, size 0x%lx\n", mem_type_str[bpi_meminfo.map[i].type], bpi_meminfo.map[i].mem_start, bpi_meminfo.map[i].mem_size);
+ }
+ }
+ bpi_meminfo.map_count = map_count;
+
+err_out:
+ early_memunmap(memmap, bpi_memmap.size);
+}
+
+static int __init bpi_parse_signature (u64 signature)
+{
+ union {
+ u64 signature;
+ char chars[9];
+ } sig;
+ sig.signature = signature;
+ sig.chars[8] = '\0';
+
+ if (!(sig.chars[0] == 'B' && sig.chars[1] == 'P' && sig.chars[2] == 'I')) {
+ pr_err("BPI: invalid signature\n");
+ return -EINVAL;
+ }
+ int version;
+ int rc = kstrtoint(&sig.chars[3], 10, &version);
+ if(rc != 0 || version == BPI_VERSION_NONE) {
+ pr_err("BPI: invalid version\n");
+ return -EINVAL;
+ }
+ bpi_version = version;
+ pr_info("BPI: version %d\n", bpi_version);
+ return 0;
+}
+
+void __init bpi_init(void)
+{
+ if (loongarch_bpi_info.bpi == EFI_INVALID_TABLE_ADDR) {
+ return;
+ }
+ struct loongarch_bpi_hdr *tbl;
+
+ tbl = early_memremap_ro(loongarch_bpi_info.bpi, sizeof(*tbl));
+ if (tbl) {
+ int rc = bpi_parse_signature(tbl->signature);
+ if (rc != 0) {
+ goto err_out;
+ }
+ have_bpi = 1;
+ if (bpi_version >= BPI_VERSION_V2) {
+ bpi_flags = tbl->flags;
+ pr_info("BPI: flags 0x%llx\n", bpi_flags);
+ }
+ unsigned long bpi_extlist = tbl->extlist;
+ parse_bpi_ext_list(bpi_extlist);
+ parse_bpi_mem_map();
+err_out:
+ early_memunmap(tbl, sizeof(*tbl));
+ }
+}
+
+void __init bpi_memblock_init(unsigned long *p_max_low_pfn)
+{
+ for(int i = 0; i < bpi_meminfo.map_count; i++) {
+ unsigned long start = bpi_meminfo.map[i].mem_start;
+ size_t size = bpi_meminfo.map[i].mem_size;
+ unsigned long end = start + size;
+
+ switch(bpi_meminfo.map[i].type) {
+ case ADDRESS_TYPE_SYSRAM:
+ // EFI_CONVENTIONAL_MEMORY
+ case ADDRESS_TYPE_PMEM:
+ // EFI_PERSISTENT_MEMORY
+ memblock_add(start, size);
+ if (*p_max_low_pfn < (end >> PAGE_SHIFT))
+ *p_max_low_pfn = end >> PAGE_SHIFT;
+ break;
+ case ADDRESS_TYPE_ACPI:
+ // EFI_ACPI_RECLAIM_MEMORY
+ memblock_add(start, size);
+ fallthrough;
+ case ADDRESS_TYPE_RESERVED:
+ // EFI_RUNTIME_SERVICES_DATA or
+ // EFI_RUNTIME_SERVICES_CODE or
+ // EFI_RESERVED_MEMORY_TYPE
+ memblock_reserve(start, size);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void __init bpi_init_node_memblock(void (*p_add_numamem_region)(u64 start, u64 end, u32 type))
+{
+ for(int i = 0; i < bpi_meminfo.map_count; i++) {
+ u64 mem_start = bpi_meminfo.map[i].mem_start;
+ u64 mem_size = bpi_meminfo.map[i].mem_size;
+ u64 mem_end = mem_start + mem_size;
+ u32 mem_type;
+
+ switch(bpi_meminfo.map[i].type) {
+ case ADDRESS_TYPE_SYSRAM:
+ mem_type = EFI_CONVENTIONAL_MEMORY;
+ p_add_numamem_region(mem_start, mem_end, mem_type);
+ break;
+ case ADDRESS_TYPE_PMEM:
+ mem_type = EFI_PERSISTENT_MEMORY;
+ p_add_numamem_region(mem_start, mem_end, mem_type);
+ break;
+ case ADDRESS_TYPE_ACPI:
+ mem_type = EFI_ACPI_RECLAIM_MEMORY;
+ p_add_numamem_region(mem_start, mem_end, mem_type);
+ fallthrough;
+ case ADDRESS_TYPE_RESERVED:
+ pr_info("Resvd: mem_type:BPI_%d, mem_start:0x%llx, mem_size:0x%llx Bytes\n",
+ bpi_meminfo.map[i].type, mem_start, mem_size);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+int loongarch_have_legacy_bpi (void){
+ return have_bpi;
+}
diff --git a/arch/loongarch/kernel/legacy_boot.h b/arch/loongarch/kernel/legacy_boot.h
new file mode 100644
index 000000000000..6d3a36ebaab7
--- /dev/null
+++ b/arch/loongarch/kernel/legacy_boot.h
@@ -0,0 +1,18 @@
+#ifndef __LEGACY_BOOT_H_
+#define __LEGACY_BOOT_H_
+
+#include <linux/efi.h>
+
+#define LOONGARCH_BPI_GUID EFI_GUID(0x4660f721, 0x2ec5, 0x416a, 0x89, 0x9a, 0x43, 0x18, 0x02, 0x50, 0xa0, 0xc9)
+
+struct loongarch_bpi_info {
+ unsigned long bpi;
+};
+
+extern struct loongarch_bpi_info loongarch_bpi_info;
+extern void bpi_init(void);
+extern void bpi_memblock_init(unsigned long *p_max_low_pfn);
+extern void bpi_init_node_memblock(void (*p_add_numamem_region)(u64 start, u64 end, u32 type));
+extern int loongarch_have_legacy_bpi(void);
+
+#endif /* __LEGACY_BOOT_H_ */
diff --git a/arch/loongarch/kernel/mem.c b/arch/loongarch/kernel/mem.c
index 86d37a447eec..b24b3db96018 100644
--- a/arch/loongarch/kernel/mem.c
+++ b/arch/loongarch/kernel/mem.c
@@ -10,6 +10,8 @@
#include <asm/loongson.h>
#include <asm/sections.h>
+#include "legacy_boot.h"
+
void __init memblock_init(void)
{
u32 mem_type;
@@ -50,6 +52,8 @@ void __init memblock_init(void)
}
}
+ bpi_memblock_init(&max_low_pfn);
+
memblock_set_current_limit(PFN_PHYS(max_low_pfn));
/* Reserve the first 2MB */
diff --git a/arch/loongarch/kernel/numa.c b/arch/loongarch/kernel/numa.c
index 8fe21f868f72..5d45c389e961 100644
--- a/arch/loongarch/kernel/numa.c
+++ b/arch/loongarch/kernel/numa.c
@@ -26,6 +26,8 @@
#include <asm/sections.h>
#include <asm/time.h>
+#include "legacy_boot.h"
+
int numa_off;
struct pglist_data *node_data[MAX_NUMNODES];
unsigned char node_distances[MAX_NUMNODES][MAX_NUMNODES];
@@ -370,6 +372,7 @@ int __init init_numa_memory(void)
return -EINVAL;
init_node_memblock();
+ bpi_init_node_memblock(add_numamem_region);
if (!memblock_validate_numa_coverage(SZ_1M))
return -EINVAL;
diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
index e8f7a54ff67c..7c8ba5f4834e 100644
--- a/arch/loongarch/kernel/setup.c
+++ b/arch/loongarch/kernel/setup.c
@@ -49,6 +49,8 @@
#include <asm/time.h>
#include <asm/unwind.h>
+#include "legacy_boot.h"
+
#define SMBIOS_BIOSSIZE_OFFSET 0x09
#define SMBIOS_BIOSEXTERN_OFFSET 0x13
#define SMBIOS_FREQLOW_OFFSET 0x16
@@ -593,6 +595,7 @@ void __init setup_arch(char **cmdline_p)
init_environ();
efi_init();
fdt_setup();
+ bpi_init();
memblock_init();
pagetable_init();
bootcmdline_init(cmdline_p);
diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c
index fd22a32755a5..16f5f9969bec 100644
--- a/arch/loongarch/kernel/smp.c
+++ b/arch/loongarch/kernel/smp.c
@@ -33,6 +33,8 @@
#include <asm/setup.h>
#include <asm/time.h>
+#include "legacy_boot.h"
+
int __cpu_number_map[NR_CPUS]; /* Map physical to logical */
EXPORT_SYMBOL(__cpu_number_map);
@@ -320,6 +322,8 @@ void loongson_boot_secondary(int cpu, struct task_struct *idle)
pr_info("Booting CPU#%d...\n", cpu);
entry = __pa_symbol((unsigned long)&smpboot_entry);
+ if (loongarch_have_legacy_bpi())
+ entry = (unsigned long)&smpboot_entry;
cpuboot_data.stack = (unsigned long)__KSTK_TOS(idle);
cpuboot_data.thread_info = (unsigned long)task_thread_info(idle);
--
2.43.0
From 46444e7f6490859748a197463473d0c65d9242b6 Mon Sep 17 00:00:00 2001
From: Miao Wang <[email protected]>
Date: Sat, 20 Jul 2024 06:32:15 +0800
Subject: [PATCH 03/11] loongarch: add MADT ACPI table conversion
On machines with legacy firmware with BPI version BPI01000, i.e. the
older version, the content of the MADT ACPI table is not following the
later finalized ACPI standard. A conversion of the content is added by
this patch. Also the patch generates and adds a MCFG table accordingly.
The above behavior is only enabled when BPI data and the BPI01000 version
is detected.
---
arch/loongarch/include/asm/acpi.h | 5 +
arch/loongarch/kernel/legacy_boot.c | 304 ++++++++++++++++++++++++++++
drivers/acpi/tables.c | 2 +
include/linux/acpi.h | 10 +
4 files changed, 321 insertions(+)
diff --git a/arch/loongarch/include/asm/acpi.h b/arch/loongarch/include/asm/acpi.h
index 49e29b29996f..473d86523b03 100644
--- a/arch/loongarch/include/asm/acpi.h
+++ b/arch/loongarch/include/asm/acpi.h
@@ -44,6 +44,11 @@ static inline u32 get_acpi_id_for_cpu(unsigned int cpu)
return acpi_core_pic[cpu_logical_map(cpu)].processor_id;
}
+#define ACPI_HAVE_ARCH_TABLE_OVERRIDE
+extern void acpi_arch_os_table_override (struct acpi_table_header *existing_table, struct acpi_table_header **new_table);
+#define ACPI_HAVE_ARCH_TABLE_INIT_COMPLETE
+extern void acpi_arch_table_init_complete(void);
+
#endif /* !CONFIG_ACPI */
#define ACPI_TABLE_UPGRADE_MAX_PHYS ARCH_LOW_ADDRESS_LIMIT
diff --git a/arch/loongarch/kernel/legacy_boot.c b/arch/loongarch/kernel/legacy_boot.c
index 30c01c8b22a0..841d8db85a3c 100644
--- a/arch/loongarch/kernel/legacy_boot.c
+++ b/arch/loongarch/kernel/legacy_boot.c
@@ -1,7 +1,13 @@
#include <linux/efi.h>
#include <linux/memblock.h>
+#include <linux/acpi.h>
+#include <linux/kmemleak.h>
+#include <linux/kernel.h>
#include <asm/early_ioremap.h>
+#include <asm/loongson.h>
+#include <asm/irq.h>
+#include <asm/numa.h>
#include "legacy_boot.h"
@@ -37,6 +43,9 @@ enum bpi_mem_type {
ADDRESS_TYPE_MAX,
};
+#define MSI_MSG_ADDRESS 0x2FF00000
+#define MSI_MSG_DEFAULT_COUNT 0xC0
+
struct loongarch_bpi_mem_map {
struct loongarch_bpi_ext_hdr header; /*{"M", "E", "M"}*/
u8 map_count;
@@ -203,6 +212,9 @@ static int __init bpi_parse_signature (u64 signature)
return 0;
}
+static void (*p_init_acpi_arch_os_table_override)(struct acpi_table_header *, struct acpi_table_header **) = NULL;
+static void init_acpi_arch_os_table_override (struct acpi_table_header *existing_table, struct acpi_table_header **new_table);
+
void __init bpi_init(void)
{
if (loongarch_bpi_info.bpi == EFI_INVALID_TABLE_ADDR) {
@@ -220,6 +232,8 @@ void __init bpi_init(void)
if (bpi_version >= BPI_VERSION_V2) {
bpi_flags = tbl->flags;
pr_info("BPI: flags 0x%llx\n", bpi_flags);
+ } else {
+ p_init_acpi_arch_os_table_override = init_acpi_arch_os_table_override;
}
unsigned long bpi_extlist = tbl->extlist;
parse_bpi_ext_list(bpi_extlist);
@@ -292,6 +306,296 @@ void __init bpi_init_node_memblock(void (*p_add_numamem_region)(u64 start, u64 e
}
}
+static u8 new_mcfg_buf [ 0
+ + sizeof(struct acpi_table_mcfg)
+ + MAX_IO_PICS * sizeof(struct acpi_mcfg_allocation)
+];
+static int __initdata new_mcfg_available = 0;
+
+void __init acpi_arch_table_init_complete(void){
+ if (!new_mcfg_available){
+ return;
+ }
+ pr_info("BPI: installing new MCFG table\n");
+ acpi_install_table((struct acpi_table_header *) new_mcfg_buf);
+}
+
+static void __init init_acpi_arch_os_table_override (struct acpi_table_header *existing_table, struct acpi_table_header **new_table){
+ static int __initdata madt_table_installed = 0;
+ static u8 new_madt_buf[ 0
+ + sizeof(struct acpi_table_madt)
+ + sizeof(struct acpi_madt_lio_pic)
+ + sizeof(struct acpi_madt_core_pic) * MAX_CORE_PIC
+ + MAX_IO_PICS * ( 0
+ + sizeof(struct acpi_madt_eio_pic)
+ + sizeof(struct acpi_madt_msi_pic)
+ + sizeof(struct acpi_madt_bio_pic)
+ )
+ ];
+ if (madt_table_installed){
+ return;
+ }
+ if (bpi_version == BPI_VERSION_NONE) {
+ return;
+ }
+ if (bpi_version > BPI_VERSION_V1) {
+ return;
+ }
+ if (strncmp(existing_table->signature, ACPI_SIG_MADT, 4) != 0) {
+ return;
+ }
+ pr_info("BPI: replacing MADT table\n");
+ struct acpi_table_madt *madt = (struct acpi_table_madt *)existing_table;
+ if (madt->header.length < sizeof(struct acpi_table_madt)) {
+ pr_warn("BPI: MADT table length %u is too small\n", madt->header.length);
+ return;
+ }
+ void *madt_end = (void *)madt + madt->header.length;
+ struct acpi_subtable_header *entry = (struct acpi_subtable_header *)(madt + 1);
+ int entry_count = 0;
+ int local_apic_count = 0;
+ int io_apic_count = 0;
+ u64 node_map = 0;
+ while((void *)entry < madt_end) {
+ unsigned int ent_len = entry->length;
+ if (ent_len < sizeof(struct acpi_subtable_header)) {
+ pr_warn("BPI: MADT entry %d length %u is too small\n", entry_count, ent_len);
+ return;
+ }
+ if((void *)entry + ent_len > madt_end) {
+ pr_warn("BPI: MADT entry %d length overflow\n", entry_count);
+ return;
+ }
+ switch(entry->type) {
+ case ACPI_MADT_TYPE_LOCAL_APIC:
+ local_apic_count++;
+ struct acpi_madt_local_apic *lapic = (struct acpi_madt_local_apic *)entry;
+ node_map |= 1 << (lapic->id / CORES_PER_EIO_NODE);
+ break;
+ case ACPI_MADT_TYPE_IO_APIC:
+ io_apic_count++;
+ break;
+ }
+ acpi_table_print_madt_entry(entry);
+
+ entry = (struct acpi_subtable_header *)((void *)entry + ent_len);
+ }
+
+ if (local_apic_count == 0) {
+ pr_warn("BPI: MADT has no local APIC entries\n");
+ return;
+ }
+ if (local_apic_count > MAX_CORE_PIC) {
+ pr_warn("BPI: MADT has too many local APIC entries\n");
+ return;
+ }
+ if (io_apic_count == 0) {
+ pr_warn("BPI: MADT has no IO APIC entries\n");
+ return;
+ }
+ if (io_apic_count > MAX_IO_PICS) {
+ pr_warn("BPI: MADT has too many IO APIC entries\n");
+ return;
+ }
+ size_t new_madt_size = sizeof(struct acpi_table_madt);
+ size_t new_mcfg_size = sizeof(struct acpi_table_mcfg);
+ new_madt_size += sizeof(struct acpi_madt_lio_pic);
+ new_madt_size += sizeof(struct acpi_madt_core_pic) * local_apic_count;
+ if (cpu_has_extioi) {
+ pr_info("BPI: Using EIOINTC interrupt mode\n");
+ new_madt_size += io_apic_count * ( 0
+ + sizeof(struct acpi_madt_eio_pic)
+ + sizeof(struct acpi_madt_msi_pic)
+ + sizeof(struct acpi_madt_bio_pic)
+ );
+ new_madt_size += sizeof(struct acpi_madt_lpc_pic);
+ new_mcfg_size += io_apic_count * sizeof(struct acpi_mcfg_allocation);
+ } else {
+ pr_info("BPI: Using HTVECINTC interrupt mode\n");
+ new_madt_size += 0;
+ new_mcfg_size += sizeof(struct acpi_mcfg_allocation);
+ }
+
+ if (new_madt_size > sizeof(new_madt_buf)) {
+ pr_warn("BPI: new madt will be too large");
+ return;
+ }
+ if (new_mcfg_size > sizeof(new_mcfg_buf)) {
+ pr_warn("BPI: new mcfg will be too large");
+ return;
+ }
+ madt_table_installed = 1;
+ new_mcfg_available = 1;
+
+ struct acpi_table_madt *new_madt = (struct acpi_table_madt *)new_madt_buf;
+
+ new_madt->header = madt->header;
+ new_madt->header.length = new_madt_size;
+ new_madt->header.checksum = 0;
+ new_madt->header.asl_compiler_id[0] = 'B';
+ new_madt->header.asl_compiler_id[1] = 'P';
+ new_madt->header.asl_compiler_id[2] = 'I';
+ new_madt->address = madt->address;
+ new_madt->flags = madt->flags;
+
+ struct acpi_table_mcfg *new_mcfg = (struct acpi_table_mcfg *)new_mcfg_buf;
+
+ memcpy(new_mcfg->header.signature, ACPI_SIG_MCFG, sizeof(new_mcfg->header.signature));
+ new_mcfg->header.length = new_mcfg_size;
+ new_mcfg->header.revision = 1;
+ new_mcfg->header.checksum = 0;
+ memcpy(new_mcfg->header.oem_id, madt->header.oem_id, sizeof(new_mcfg->header.oem_id));
+ memcpy(new_mcfg->header.oem_table_id, madt->header.oem_table_id, sizeof(new_mcfg->header.oem_table_id));
+ new_mcfg->header.oem_revision = madt->header.oem_revision;
+ memcpy(new_mcfg->header.asl_compiler_id, "BPI", sizeof(new_mcfg->header.asl_compiler_id));
+ new_mcfg->header.asl_compiler_revision = 1;
+ memset(new_mcfg->reserved, 0, sizeof(new_mcfg->reserved));
+
+ struct acpi_mcfg_allocation *mcfg_entry = (struct acpi_mcfg_allocation *)(new_mcfg + 1);
+
+ static struct acpi_madt_core_pic __initdata core_pics[MAX_CORE_PIC];
+ static struct acpi_madt_eio_pic __initdata eio_pics[MAX_IO_PICS];
+ static struct acpi_madt_msi_pic __initdata msi_pics[MAX_IO_PICS];
+ static struct acpi_madt_bio_pic __initdata bio_pics[MAX_IO_PICS];
+
+ entry = (struct acpi_subtable_header *)(madt + 1);
+ int core_idx = 0;
+ int eio_idx = 0;
+ while((void *)entry < madt_end) {
+ unsigned int ent_len = entry->length;
+ if(entry->type == ACPI_MADT_TYPE_LOCAL_APIC) {
+ struct acpi_madt_local_apic *lapic = (struct acpi_madt_local_apic *)entry;
+
+ if(core_idx >= local_apic_count){
+ panic("BPI: MADT local APIC entries are more than expected\n");
+ }
+
+ core_pics[core_idx].header.type = ACPI_MADT_TYPE_CORE_PIC;
+ core_pics[core_idx].header.length = sizeof(core_pics[0]);
+ core_pics[core_idx].version = ACPI_MADT_CORE_PIC_VERSION_V1;
+ core_pics[core_idx].processor_id = lapic->processor_id;
+ core_pics[core_idx].core_id = lapic->id;
+ core_pics[core_idx].flags = lapic->lapic_flags;
+
+ core_idx++;
+ }else if(entry->type == ACPI_MADT_TYPE_IO_APIC) {
+ struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry;
+
+ if(eio_idx >= io_apic_count){
+ panic("BPI: MADT IO APIC entries are more than expected\n");
+ }
+
+ eio_pics[eio_idx].header.type = ACPI_MADT_TYPE_EIO_PIC;
+ eio_pics[eio_idx].header.length = sizeof(eio_pics[0]);
+ eio_pics[eio_idx].version = ACPI_MADT_EIO_PIC_VERSION_V1;
+ eio_pics[eio_idx].cascade = 3 + eio_idx;
+ eio_pics[eio_idx].node = ioapic->id;
+ if(eio_idx == 0){
+ eio_pics[eio_idx].node_map = node_map;
+ }else{
+ eio_pics[0].node_map = node_map & 0x0f0f0f0f0f0f0f0full;
+ eio_pics[eio_idx].node_map = node_map & 0xf0f0f0f0f0f0f0f0ull;
+ }
+
+ unsigned long addr = ioapic->address;
+ if(eio_idx > 0){
+ addr |= nid_to_addrbase(ioapic->id) | HT1LO_OFFSET;
+ }
+
+ msi_pics[eio_idx].header.type = ACPI_MADT_TYPE_MSI_PIC;
+ msi_pics[eio_idx].header.length = sizeof(msi_pics[0]);
+ msi_pics[eio_idx].version = ACPI_MADT_MSI_PIC_VERSION_V1;
+ msi_pics[eio_idx].msg_address = MSI_MSG_ADDRESS;
+ pr_info("BPI: will read MSI start addr for node %d from 0x%lx\n", ioapic->id, addr);
+ msi_pics[eio_idx].start = (((unsigned long)ls7a_readq(addr) >> 48) & 0xff) + 1;
+ pr_info("BPI: done read MSI start addr for node %d from 0x%lx\n", ioapic->id, addr);
+ msi_pics[eio_idx].count = MSI_MSG_DEFAULT_COUNT;
+
+ bio_pics[eio_idx].header.type = ACPI_MADT_TYPE_BIO_PIC;
+ bio_pics[eio_idx].header.length = sizeof(bio_pics[0]);
+ bio_pics[eio_idx].version = ACPI_MADT_BIO_PIC_VERSION_V1;
+ bio_pics[eio_idx].address = addr;
+ bio_pics[eio_idx].size = 0x1000;
+ bio_pics[eio_idx].id = ioapic->id;
+ bio_pics[eio_idx].gsi_base = ioapic->global_irq_base;
+
+ mcfg_entry->address = mcfg_addr_init(ioapic->id);
+ mcfg_entry->pci_segment = eio_idx;
+ mcfg_entry->start_bus_number = 0;
+ mcfg_entry->end_bus_number = 0xFF; // Who knows?
+ mcfg_entry->reserved = 0;
+ mcfg_entry++;
+
+ eio_idx++;
+ }
+ entry = (struct acpi_subtable_header *)((void *)entry + ent_len);
+ }
+ if(eio_idx != io_apic_count || core_idx != local_apic_count) {
+ panic("BPI: MADT entries are less than expected\n");
+ }
+
+ // 1. Core APIC 0x11
+ struct acpi_subtable_header *new_entry = (struct acpi_subtable_header *)(new_madt + 1);
+
+ memcpy(new_entry, core_pics, local_apic_count * sizeof(core_pics[0]));
+ new_entry = (struct acpi_subtable_header *)((void *)new_entry + local_apic_count * sizeof(core_pics[0]));
+
+ // 2. LIO PIC 0x12
+ {
+ struct acpi_madt_lio_pic *lio_pic = (struct acpi_madt_lio_pic *)new_entry;
+ lio_pic->header.type = ACPI_MADT_TYPE_LIO_PIC;
+ lio_pic->header.length = sizeof(*lio_pic);
+ lio_pic->version = ACPI_MADT_LIO_PIC_VERSION_V1;
+ lio_pic->address = LOONGSON_REG_BASE + 0x1400;
+ lio_pic->size = 256;
+ lio_pic->cascade[0] = 2;
+ lio_pic->cascade[1] = 3;
+ lio_pic->cascade_map[0] = 0x00FFFFFF;
+ lio_pic->cascade_map[1] = 0xFF000000;
+ new_entry = (struct acpi_subtable_header *)((void *)new_entry + sizeof(*lio_pic));
+ }
+ // 3. HT PIC 0x13
+ if (!cpu_has_extioi) {
+ // FIX ME: Unsupported
+ } else {
+ // 4. EIO PIC 0x14
+ memcpy(new_entry, eio_pics, io_apic_count * sizeof(eio_pics[0]));
+ new_entry = (struct acpi_subtable_header *)((void *)new_entry + io_apic_count * sizeof(eio_pics[0]));
+ // 5. MSI PIC 0x15
+ memcpy(new_entry, msi_pics, io_apic_count * sizeof(msi_pics[0]));
+ new_entry = (struct acpi_subtable_header *)((void *)new_entry + io_apic_count * sizeof(msi_pics[0]));
+ // 6. BIO PIC 0x16
+ memcpy(new_entry, bio_pics, io_apic_count * sizeof(bio_pics[0]));
+ new_entry = (struct acpi_subtable_header *)((void *)new_entry + io_apic_count * sizeof(bio_pics[0]));
+ // 7. LPC PIC 0x17
+ {
+ struct acpi_madt_lpc_pic *lpc_pic = (struct acpi_madt_lpc_pic *)new_entry;
+ lpc_pic->header.type = ACPI_MADT_TYPE_LPC_PIC;
+ lpc_pic->header.length = sizeof(*lpc_pic);
+ lpc_pic->version = ACPI_MADT_LPC_PIC_VERSION_V1;
+ lpc_pic->address = LS7A_LPC_REG_BASE;
+ lpc_pic->size = SZ_4K;
+ lpc_pic->cascade = 19;
+ new_entry = (struct acpi_subtable_header *)((void *)new_entry + sizeof(*lpc_pic));
+ }
+ }
+ if((void *)new_entry != (void *)new_madt + new_madt_size) {
+ panic("BPI: missing bytes while constructing new MADT\n");
+ }
+ if((void *)mcfg_entry != (void *)new_mcfg + new_mcfg_size) {
+ panic("BPI: missing bytes while constructing new MCFG\n");
+ }
+ new_madt->header.checksum = 0 - ext_listhdr_checksum((u8 *)new_madt, new_madt_size);
+ new_mcfg->header.checksum = 0 - ext_listhdr_checksum((u8 *)new_mcfg, new_mcfg_size);
+ *new_table = (struct acpi_table_header *)new_madt;
+}
+
+void acpi_arch_os_table_override (struct acpi_table_header *existing_table, struct acpi_table_header **new_table){
+ if(p_init_acpi_arch_os_table_override && system_state == SYSTEM_BOOTING) {
+ p_init_acpi_arch_os_table_override(existing_table, new_table);
+ }
+}
+
int loongarch_have_legacy_bpi (void){
return have_bpi;
}
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index b976e5fc3fbc..6cd17bb24426 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -679,6 +679,7 @@ acpi_status acpi_os_table_override(struct acpi_table_header *existing_table,
*new_table = (struct acpi_table_header *)&dsdt_amlcode;
}
#endif
+ acpi_arch_os_table_override(existing_table, new_table);
if (*new_table != NULL)
acpi_table_taint(existing_table);
return AE_OK;
@@ -734,6 +735,7 @@ void __init acpi_table_init_complete(void)
{
acpi_table_initrd_scan();
check_multiple_madt();
+ acpi_arch_table_init_complete();
}
int __init acpi_table_init(void)
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 168201e4c782..6e1a550c675e 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -769,6 +769,16 @@ static inline u64 acpi_arch_get_root_pointer(void)
int acpi_get_local_address(acpi_handle handle, u32 *addr);
const char *acpi_get_subsystem_id(acpi_handle handle);
+#ifndef ACPI_HAVE_ARCH_TABLE_OVERRIDE
+static inline void acpi_arch_os_table_override (struct acpi_table_header *existing_table, struct acpi_table_header **new_table){
+}
+#endif
+#ifndef ACPI_HAVE_ARCH_TABLE_INIT_COMPLETE
+static inline void acpi_arch_table_init_complete(void)
+{
+}
+#endif
+
#else /* !CONFIG_ACPI */
#define acpi_disabled 1
--
2.43.0
From 0377c038ec4715fae827e33b58a968f133dd4750 Mon Sep 17 00:00:00 2001
From: Miao Wang <[email protected]>
Date: Wed, 24 Jul 2024 09:06:27 +0800
Subject: [PATCH 04/11] loongarch: correct missing offset of PCI root
controller in DSDT table
On machines with legacy firmware with BPI version BPI01000, the PCI root
controller information in the DSDT table lacks AddressTranslation in its
WordIO resource defination, causing the failure of the registration for the
LIO address space. This patch corrects this issue when the given offset
is zero for the PCI root controller.
This patch also fixes the lack of the leading 16K, i.e. ISA_IOSIZE, in
the defination of WordIO resource. This is because that address range is
registered unconditionally on the legacy loongarch linux port.
This patch also fixes the start addresses or end addresses of WordIO
resource not aligned to the page size by rouding the addresses up to the
nearest page starting.
The above behavior is only enabled when BPI data and the BPI01000 version
is detected.
---
arch/loongarch/include/asm/acpi.h | 2 ++
arch/loongarch/kernel/legacy_boot.c | 23 ++++++++++++++++++++++-
drivers/acpi/pci_root.c | 1 +
include/linux/pci-acpi.h | 4 ++++
4 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/arch/loongarch/include/asm/acpi.h b/arch/loongarch/include/asm/acpi.h
index 473d86523b03..ecf05448fe9d 100644
--- a/arch/loongarch/include/asm/acpi.h
+++ b/arch/loongarch/include/asm/acpi.h
@@ -48,6 +48,8 @@ static inline u32 get_acpi_id_for_cpu(unsigned int cpu)
extern void acpi_arch_os_table_override (struct acpi_table_header *existing_table, struct acpi_table_header **new_table);
#define ACPI_HAVE_ARCH_TABLE_INIT_COMPLETE
extern void acpi_arch_table_init_complete(void);
+#define ACPI_HAVE_ARCH_PCI_ROOT_RES_FILTER
+extern void acpi_arch_pci_probe_root_dev_filter(struct resource_entry *entry);
#endif /* !CONFIG_ACPI */
diff --git a/arch/loongarch/kernel/legacy_boot.c b/arch/loongarch/kernel/legacy_boot.c
index 841d8db85a3c..7043bfd0399d 100644
--- a/arch/loongarch/kernel/legacy_boot.c
+++ b/arch/loongarch/kernel/legacy_boot.c
@@ -60,7 +60,7 @@ struct loongarch_bpi_info __initdata loongarch_bpi_info = {
.bpi = EFI_INVALID_TABLE_ADDR,
};
-static enum bpi_vers __initdata bpi_version = BPI_VERSION_NONE;
+static enum bpi_vers bpi_version = BPI_VERSION_NONE;
static u64 __initdata bpi_flags = 0;
static int have_bpi = 0;
@@ -596,6 +596,27 @@ void acpi_arch_os_table_override (struct acpi_table_header *existing_table, stru
}
}
+void acpi_arch_pci_probe_root_dev_filter(struct resource_entry *entry)
+{
+ if (bpi_version == BPI_VERSION_NONE) {
+ return;
+ }
+ if (bpi_version > BPI_VERSION_V1) {
+ return;
+ }
+
+ if (entry->res->flags & IORESOURCE_IO) {
+ if (entry->offset == 0) {
+ if (entry->res->start == ISA_IOSIZE) {
+ entry->res->start = 0;
+ }
+ entry->offset = LOONGSON_LIO_BASE;
+ entry->res->start = LOONGSON_LIO_BASE + PFN_ALIGN(entry->res->start);
+ entry->res->end = LOONGSON_LIO_BASE + PFN_ALIGN(entry->res->end + 1) - 1;
+ }
+ }
+}
+
int loongarch_have_legacy_bpi (void){
return have_bpi;
}
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 58b89b8d950e..93936225dc37 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -914,6 +914,7 @@ int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
"no IO and memory resources present in _CRS\n");
else {
resource_list_for_each_entry_safe(entry, tmp, list) {
+ acpi_arch_pci_probe_root_dev_filter(entry);
if (entry->res->flags & IORESOURCE_IO)
acpi_pci_root_remap_iospace(&device->fwnode,
entry);
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index 078225b514d4..1c22ca4ec794 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -133,6 +133,10 @@ static inline void pci_acpi_remove_edr_notifier(struct pci_dev *pdev) { }
int pci_acpi_set_companion_lookup_hook(struct acpi_device *(*func)(struct pci_dev *));
void pci_acpi_clear_companion_lookup_hook(void);
+#ifndef ACPI_HAVE_ARCH_PCI_ROOT_RES_FILTER
+static inline void acpi_arch_pci_probe_root_dev_filter(struct resource_entry *entry) { }
+#endif
+
#else /* CONFIG_ACPI */
static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
--
2.43.0
From ef42b569a385e2b6e6126590f29d5116ae2547a3 Mon Sep 17 00:00:00 2001
From: Miao Wang <[email protected]>
Date: Thu, 25 Jul 2024 16:09:19 +0800
Subject: [PATCH 05/11] loongarch: fix missing dependency info in DSDT
On machines with legacy firmware with BPI01000 version, the devices on
the LIO bus lackes the dependency on the PCI root controller, causing
the memory-mapped address of the legacy IO ports read before the setup
of the mapping, resulting in kernel panic. Such DSDT can work on the
legacy loongarch linux port because the leading 16K is unconditionally
registered, before the enumeration of the devices in the DSDT table.
This patch addes such dependency info, to order the initialization of
the devices on the LIO bus after the initialization of the PCI root
controller, fixing this problem. However, the addition should be done on
each possible LIO device, and currently the patch only includes the
legacy EC device on some laptops located at the path \_SB.PCI0.LPC.EC.
Thus, this patch will be improved to include more devices.
The above behavior is only enabled when BPI data and the BPI01000 version
is detected.
---
arch/loongarch/include/asm/acpi.h | 2 ++
arch/loongarch/kernel/legacy_boot.c | 47 +++++++++++++++++++++++++++++
drivers/acpi/bus.c | 1 +
include/linux/acpi.h | 4 +++
4 files changed, 54 insertions(+)
diff --git a/arch/loongarch/include/asm/acpi.h b/arch/loongarch/include/asm/acpi.h
index ecf05448fe9d..915cb0a2c239 100644
--- a/arch/loongarch/include/asm/acpi.h
+++ b/arch/loongarch/include/asm/acpi.h
@@ -50,6 +50,8 @@ extern void acpi_arch_os_table_override (struct acpi_table_header *existing_tabl
extern void acpi_arch_table_init_complete(void);
#define ACPI_HAVE_ARCH_PCI_ROOT_RES_FILTER
extern void acpi_arch_pci_probe_root_dev_filter(struct resource_entry *entry);
+#define ACPI_HAVE_ARCH_INIT
+extern void acpi_arch_init(void);
#endif /* !CONFIG_ACPI */
diff --git a/arch/loongarch/kernel/legacy_boot.c b/arch/loongarch/kernel/legacy_boot.c
index 7043bfd0399d..3ec69ffd8b94 100644
--- a/arch/loongarch/kernel/legacy_boot.c
+++ b/arch/loongarch/kernel/legacy_boot.c
@@ -617,6 +617,53 @@ void acpi_arch_pci_probe_root_dev_filter(struct resource_entry *entry)
}
}
+static __initconst const struct {
+ struct acpi_table_header header;
+ unsigned char code [];
+} __packed dsdt_add_aml_code = {
+ .header = {
+ .signature = ACPI_SIG_DSDT
+ },
+ .code = {
+ 0x14,0x21,0x5C,0x2F, /* 00000020 " .!\/" */
+ 0x05,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00000028 "._SB_PCI" */
+ 0x30,0x4C,0x50,0x43,0x5F,0x45,0x43,0x5F, /* 00000030 "0LPC_EC_" */
+ 0x5F,0x5F,0x44,0x45,0x50,0x08,0xA4,0x12, /* 00000038 "__DEP..." */
+ 0x06,0x01,0x50,0x43,0x49,0x30 /* 00000040 "..PCI0" */
+ },
+};
+
+void __init acpi_arch_init (){
+ if (bpi_version == BPI_VERSION_NONE) {
+ return;
+ }
+ if (bpi_version > BPI_VERSION_V1) {
+ return;
+ }
+ pr_info("BPI: Trying to patch DSDT\n");
+
+ acpi_status status;
+ acpi_handle handle;
+
+ status = acpi_get_handle(NULL, "\\_SB.PCI0.LPC.EC", &handle);
+ if (ACPI_FAILURE(status)) {
+ if (status != AE_NOT_FOUND) {
+ pr_info("BPI: Unable to find EC device: %s\n", acpi_format_exception(status));
+ }
+ return;
+ }
+ if (acpi_has_method(handle, "_DEP")) {
+ return;
+ }
+
+ status = acpi_install_method((u8 *)&dsdt_add_aml_code);
+ if (ACPI_FAILURE(status)) {
+ pr_info("BPI: Unable to patch DSDT(0x%x)\n", status);
+ return;
+ }
+ acpi_handle_info(handle, "BPI: Patched DSDT\n");
+}
+
int loongarch_have_legacy_bpi (void){
return have_bpi;
}
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index a87b10eef77d..44920caedf8f 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -1445,6 +1445,7 @@ static int __init acpi_init(void)
acpi_hest_init();
acpi_ghes_init();
acpi_arm_init();
+ acpi_arch_init();
acpi_scan_init();
acpi_ec_init();
acpi_debugfs_init();
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 6e1a550c675e..0917301171e7 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -1533,6 +1533,10 @@ void acpi_arm_init(void);
static inline void acpi_arm_init(void) { }
#endif
+#ifndef ACPI_HAVE_ARCH_INIT
+static inline void acpi_arch_init(void) {}
+#endif
+
#ifdef CONFIG_ACPI_PCC
void acpi_init_pcc(void);
#else
--
2.43.0
From 6db3770e4ed1d6d2cd53f485ac2c0fbd7685aa83 Mon Sep 17 00:00:00 2001
From: Miao Wang <[email protected]>
Date: Tue, 13 Aug 2024 16:05:28 +0800
Subject: [PATCH 06/11] loongarch: fix DMA address offset
Loongarch CPUs are using HT bus interface, which is only 40-bit wide,
to communicate with the bridge chipset. However, the actual memory
bus of the CPUs is 48-bit wide, and the available address space of DMA
requests of PCI devices is also larger than the 40-bit address space.
The address space of loongarch systems is not continuous, the bits
[47:44] of which are used to denote the belonging node id, which is
far beyond the space provided by the 40-bit wide HT bus. As a result,
a translation on the both LS7A and CPU sides is needed.
The translation happens on the LS7A side is controlled by the higher
half of the register, HT_ROUTE. Bits [12:8] denotes dma_node_id_offset
and bits[15:13] denotes dma_node_id_offset_mapped. The behavior of the
translation is that the chip extracts the node id from bit
dma_node_id_offset + 36 of a DMA address, places it at bit
dma_node_id_offset_mapped + 32, and generates the address on the HT bus.
On the CPU side, an alike translation happens, to convert the address on
the HT bus back to a proper memory address.
On machines with legacy firmware with BPI01000 version,
dma_node_id_offset is configured with 0, resulting the address which
should be used by the DMA engine of a PCI device differs from the
actural physical memeory address, which requires a pair of arch-specific
phys_to_dma and dma_to_phys functions or setting up the whole mapping
in the _DMA method of the PCI root device in the DSDT table.
The former method requires we add back the prevoiusly removed functions,
and the latter method degrades the performance since when the
translation happens, the mapping table is scanned linearly.
This patch addresses this issue by directly setting dma_node_id_offset
to 8, like what is done by modern firmwares, making the address used by
the DMA engine just the same as the actual physical memory address, and
eliminating the need of DMA address translation on the kernel side.
---
arch/loongarch/kernel/legacy_boot.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/arch/loongarch/kernel/legacy_boot.c b/arch/loongarch/kernel/legacy_boot.c
index 3ec69ffd8b94..2888e2b9fb45 100644
--- a/arch/loongarch/kernel/legacy_boot.c
+++ b/arch/loongarch/kernel/legacy_boot.c
@@ -46,6 +46,19 @@ enum bpi_mem_type {
#define MSI_MSG_ADDRESS 0x2FF00000
#define MSI_MSG_DEFAULT_COUNT 0xC0
+/*
+ ``This should be configured by firmware"
+ -- Section 4, Page 25 of Loongson-7A1000 User Manual v2.0
+ but unable to figure out the exact value.
+ The manual gives a typical value in Table 3.2, Page 23.
+*/
+#define LS7A_CHIPCFG_REG_OFF 0x00010000
+
+/* Section 4.1, Page 26 of Loongson-7A1000 User Manual v2.0 */
+#define LS7A_DMA_CFG_OFF 0x041c
+#define LS7A_DMA_NODE_ID_OFFSET_SHF 8
+#define LS7A_DMA_NODE_ID_OFFSET_MASK GENMASK(12, 8)
+
struct loongarch_bpi_mem_map {
struct loongarch_bpi_ext_hdr header; /*{"M", "E", "M"}*/
u8 map_count;
@@ -588,6 +601,20 @@ static void __init init_acpi_arch_os_table_override (struct acpi_table_header *e
new_madt->header.checksum = 0 - ext_listhdr_checksum((u8 *)new_madt, new_madt_size);
new_mcfg->header.checksum = 0 - ext_listhdr_checksum((u8 *)new_mcfg, new_mcfg_size);
*new_table = (struct acpi_table_header *)new_madt;
+
+ // Override LS7A dma_node_id_offset
+ for(int i = 0; i < io_apic_count; i++){
+ u64 ls7a_base_addr = bio_pics[i].address;
+ void __iomem *dma_node_id_addr = (void __iomem *) TO_UNCACHE(ls7a_base_addr + LS7A_CHIPCFG_REG_OFF + LS7A_DMA_CFG_OFF);
+ u32 dma_cfg = readl(dma_node_id_addr);
+ u32 dma_node_id_offset = (dma_cfg & LS7A_DMA_NODE_ID_OFFSET_MASK) >> LS7A_DMA_NODE_ID_OFFSET_SHF;
+ if(dma_node_id_offset != 8){
+ pr_info("BPI: LS7A %d DMA node id offset is %d, will set to 8\n", i, dma_node_id_offset);
+ dma_cfg &= ~LS7A_DMA_NODE_ID_OFFSET_MASK;
+ dma_cfg |= 8 << LS7A_DMA_NODE_ID_OFFSET_SHF;
+ writel(dma_cfg, dma_node_id_addr);
+ }
+ }
}
void acpi_arch_os_table_override (struct acpi_table_header *existing_table, struct acpi_table_header **new_table){
--
2.43.0
From b169ab6f172daad9072189aaea645a51dbe37bb2 Mon Sep 17 00:00:00 2001
From: Miao Wang <[email protected]>
Date: Tue, 13 Aug 2024 22:33:01 +0800
Subject: [PATCH 07/11] loongarch: fix HT_RX_INT_TRANS register
On machines with legacy firmware with BPI01000 version, the
HT_RX_INT_TRANS register on the node 5, i.e. the node connected with the
second LS7A bridge chip, is not initialized correctly, causing the
failure of the delivery of interrupts from PCIe devices connected to the
second LS7A bridge chip.
This patch fixes this by correctly pointing the HT_RX_INT_TRANS register
to the EXT_IOI_SEND_OFF register on the corresponding node.
---
arch/loongarch/kernel/legacy_boot.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/arch/loongarch/kernel/legacy_boot.c b/arch/loongarch/kernel/legacy_boot.c
index 2888e2b9fb45..204b33109f37 100644
--- a/arch/loongarch/kernel/legacy_boot.c
+++ b/arch/loongarch/kernel/legacy_boot.c
@@ -59,6 +59,16 @@ enum bpi_mem_type {
#define LS7A_DMA_NODE_ID_OFFSET_SHF 8
#define LS7A_DMA_NODE_ID_OFFSET_MASK GENMASK(12, 8)
+/* Section 14.4.1, Page 100 of Loongson-3A5000 User Manual v1.03 */
+#define HT_CTRL_CFG_OFF 0xfdfb000000ull
+/* Section 14.5.34, Page 141 of Loongson-3A5000 User Manual v1.03 */
+#define HT_CTRL_HT_RX_INT_TRANS_LO_OFF 0x270
+#define HT_CTRL_HT_RX_INT_TRANS_HI_OFF 0x274
+#define HT_CTRL_HT_RX_INT_TRANS_INT_TRANS_ALLOW BIT(30)
+
+/* Section 11.2.3, Page 61 of Loongson-3A5000 User Manual v1.03 */
+#define EXT_IOI_SEND_OFF 0x1140
+
struct loongarch_bpi_mem_map {
struct loongarch_bpi_ext_hdr header; /*{"M", "E", "M"}*/
u8 map_count;
@@ -615,6 +625,20 @@ static void __init init_acpi_arch_os_table_override (struct acpi_table_header *e
writel(dma_cfg, dma_node_id_addr);
}
}
+
+ // Override HT_RX_INT_TRANS
+ for(int i = 0; i < io_apic_count; i++){
+ unsigned int node = eio_pics[i].node;
+ void __iomem *ht_rx_int_trans_hi = (void __iomem *) TO_UNCACHE(nid_to_addrbase(node) + HT1LO_OFFSET + HT_CTRL_CFG_OFF + HT_CTRL_HT_RX_INT_TRANS_HI_OFF);
+ void __iomem *ht_rx_int_trans_lo = (void __iomem *) TO_UNCACHE(nid_to_addrbase(node) + HT1LO_OFFSET + HT_CTRL_CFG_OFF + HT_CTRL_HT_RX_INT_TRANS_LO_OFF);
+ u64 ext_ioi_addr = nid_to_addrbase(node) + LOONGSON_REG_BASE + EXT_IOI_SEND_OFF;
+ u64 ht_rx_int_trans_cfg_orig = ((u64)readl(ht_rx_int_trans_hi) << 32) | readl(ht_rx_int_trans_lo);
+ u32 ht_rx_int_trans_cfg_hi = HT_CTRL_HT_RX_INT_TRANS_INT_TRANS_ALLOW | (ext_ioi_addr >> 32);
+ u32 ht_rx_int_trans_cfg_lo = ext_ioi_addr & GENMASK(31, 0);
+ pr_info("BPI: HT controller on node %u RX_INT_TRANS is 0x%llx, will set to 0x%llx\n", node, ht_rx_int_trans_cfg_orig, ((u64)ht_rx_int_trans_cfg_hi << 32) | ht_rx_int_trans_cfg_lo);
+ writel(ht_rx_int_trans_cfg_hi, ht_rx_int_trans_hi);
+ writel(ht_rx_int_trans_cfg_lo, ht_rx_int_trans_lo);
+ }
}
void acpi_arch_os_table_override (struct acpi_table_header *existing_table, struct acpi_table_header **new_table){
--
2.43.0
From 071d075f7f8e24acf9a4d5f38b69181cb13fc50b Mon Sep 17 00:00:00 2001
From: Miao Wang <[email protected]>
Date: Wed, 17 Jul 2024 08:44:09 +0800
Subject: [PATCH 08/11] loongarch: add earlyprintk for debugging
---
arch/loongarch/kernel/Makefile | 1 +
arch/loongarch/kernel/early_printk.c | 54 ++++++++++++++++++++++++++++
2 files changed, 55 insertions(+)
create mode 100644 arch/loongarch/kernel/early_printk.c
diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
index 84d2e2d896ab..796466f366c4 100644
--- a/arch/loongarch/kernel/Makefile
+++ b/arch/loongarch/kernel/Makefile
@@ -80,3 +80,4 @@ obj-$(CONFIG_JUMP_LABEL) += jump_label.o
CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS)
obj-y += legacy_boot.o
+obj-y += early_printk.o
diff --git a/arch/loongarch/kernel/early_printk.c b/arch/loongarch/kernel/early_printk.c
new file mode 100644
index 000000000000..764650a46264
--- /dev/null
+++ b/arch/loongarch/kernel/early_printk.c
@@ -0,0 +1,54 @@
+#include <linux/console.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/serial_reg.h>
+#include <linux/serial.h>
+#include <asm/addrspace.h>
+#include <asm/io.h>
+
+#define LOONGUART1 0x1fe001e0
+
+static void loong_uart_putc(unsigned char c){
+ *(volatile unsigned char *)TO_UNCACHE(LOONGUART1 + UART_TX) = c;
+ int status;
+ for(int count = 0; count < 25000000; count++){
+ status = *(volatile unsigned char *)TO_UNCACHE(LOONGUART1 + UART_LSR);
+ if (uart_lsr_tx_empty(status))
+ break;
+ cpu_relax();
+ }
+}
+
+static void early_serial_write(struct console *con, const char *s, unsigned n){
+ while(*s && n-- > 0){
+ if ( *s == '\n' ){
+ loong_uart_putc('\r');
+ }
+ loong_uart_putc(*s);
+ s++;
+ }
+}
+
+static struct console early_serial_console = {
+ .name = "earlyser",
+ .write = early_serial_write,
+ .flags = CON_PRINTBUFFER | CON_BOOT,
+ .index = -1,
+};
+
+static int __init setup_early_printk(char *buf)
+{
+ static int registered = 0;
+ if (registered) {
+ return 0;
+ }
+ if (early_serial_console.index != -1) {
+ return 0;
+ }
+ register_console(&early_serial_console);
+ return 0;
+}
+
+early_param("earlyprintk", setup_early_printk);
--
2.43.0
From c72f41853fc908ea8de437af7cc3e311c8fbc926 Mon Sep 17 00:00:00 2001
From: Miao Wang <[email protected]>
Date: Wed, 17 Jul 2024 09:03:32 +0800
Subject: [PATCH 09/11] loongarch: add debug outputs
---
arch/loongarch/include/uartout.h | 24 ++++++++++++
arch/loongarch/kernel/efi.c | 1 +
arch/loongarch/kernel/legacy_boot.c | 11 ++++++
arch/loongarch/kernel/numa.c | 17 +++++++++
arch/loongarch/kernel/setup.c | 37 +++++++++++++++++++
arch/loongarch/kernel/smp.c | 13 +++++++
drivers/firmware/efi/libstub/efi-stub-entry.c | 2 +
drivers/firmware/efi/libstub/loongarch.c | 10 +++++
drivers/firmware/efi/libstub/zboot.c | 5 +++
init/main.c | 15 ++++++++
10 files changed, 135 insertions(+)
create mode 100644 arch/loongarch/include/uartout.h
diff --git a/arch/loongarch/include/uartout.h b/arch/loongarch/include/uartout.h
new file mode 100644
index 000000000000..06023fa03deb
--- /dev/null
+++ b/arch/loongarch/include/uartout.h
@@ -0,0 +1,24 @@
+#include <linux/serial_reg.h>
+#include <linux/serial.h>
+#include <asm/addrspace.h>
+#include <asm/io.h>
+
+#define LOONGUART1 0x1fe001e0
+
+static inline void loong_uart_putc(unsigned char c){
+ *(volatile unsigned char *)TO_UNCACHE(LOONGUART1 + UART_TX) = c;
+ int status;
+ for(int count = 0; count < 25000000; count++){
+ status = *(volatile unsigned char *)TO_UNCACHE(LOONGUART1 + UART_LSR);
+ if (uart_lsr_tx_empty(status))
+ break;
+ cpu_relax();
+ }
+}
+
+static inline void loong_uart_puts(const char *str){
+ while(*str){
+ loong_uart_putc(*str);
+ str++;
+ }
+}
diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c
index 307f35d1e71f..3db8e859592b 100644
--- a/arch/loongarch/kernel/efi.c
+++ b/arch/loongarch/kernel/efi.c
@@ -63,6 +63,7 @@ void __init efi_runtime_init(void)
}
efi.runtime = (efi_runtime_services_t *)efi_systab->runtime;
+ pr_info("efi_systab->runtime=0x%lx\n", (unsigned long) efi_systab->runtime);
efi.runtime_version = (unsigned int)efi.runtime->hdr.revision;
efi_native_runtime_setup();
diff --git a/arch/loongarch/kernel/legacy_boot.c b/arch/loongarch/kernel/legacy_boot.c
index 204b33109f37..a89cddff589f 100644
--- a/arch/loongarch/kernel/legacy_boot.c
+++ b/arch/loongarch/kernel/legacy_boot.c
@@ -559,9 +559,11 @@ static void __init init_acpi_arch_os_table_override (struct acpi_table_header *e
// 1. Core APIC 0x11
struct acpi_subtable_header *new_entry = (struct acpi_subtable_header *)(new_madt + 1);
+ pr_info("new_entry = %lx\n", (unsigned long)new_entry);
memcpy(new_entry, core_pics, local_apic_count * sizeof(core_pics[0]));
new_entry = (struct acpi_subtable_header *)((void *)new_entry + local_apic_count * sizeof(core_pics[0]));
+ pr_info("new_entry = %lx\n", (unsigned long)new_entry);
// 2. LIO PIC 0x12
{
@@ -576,6 +578,7 @@ static void __init init_acpi_arch_os_table_override (struct acpi_table_header *e
lio_pic->cascade_map[0] = 0x00FFFFFF;
lio_pic->cascade_map[1] = 0xFF000000;
new_entry = (struct acpi_subtable_header *)((void *)new_entry + sizeof(*lio_pic));
+ pr_info("new_entry = %lx\n", (unsigned long)new_entry);
}
// 3. HT PIC 0x13
if (!cpu_has_extioi) {
@@ -584,12 +587,15 @@ static void __init init_acpi_arch_os_table_override (struct acpi_table_header *e
// 4. EIO PIC 0x14
memcpy(new_entry, eio_pics, io_apic_count * sizeof(eio_pics[0]));
new_entry = (struct acpi_subtable_header *)((void *)new_entry + io_apic_count * sizeof(eio_pics[0]));
+ pr_info("new_entry = %lx\n", (unsigned long)new_entry);
// 5. MSI PIC 0x15
memcpy(new_entry, msi_pics, io_apic_count * sizeof(msi_pics[0]));
new_entry = (struct acpi_subtable_header *)((void *)new_entry + io_apic_count * sizeof(msi_pics[0]));
+ pr_info("new_entry = %lx\n", (unsigned long)new_entry);
// 6. BIO PIC 0x16
memcpy(new_entry, bio_pics, io_apic_count * sizeof(bio_pics[0]));
new_entry = (struct acpi_subtable_header *)((void *)new_entry + io_apic_count * sizeof(bio_pics[0]));
+ pr_info("new_entry = %lx\n", (unsigned long)new_entry);
// 7. LPC PIC 0x17
{
struct acpi_madt_lpc_pic *lpc_pic = (struct acpi_madt_lpc_pic *)new_entry;
@@ -600,16 +606,21 @@ static void __init init_acpi_arch_os_table_override (struct acpi_table_header *e
lpc_pic->size = SZ_4K;
lpc_pic->cascade = 19;
new_entry = (struct acpi_subtable_header *)((void *)new_entry + sizeof(*lpc_pic));
+ pr_info("new_entry = %lx\n", (unsigned long)new_entry);
}
}
if((void *)new_entry != (void *)new_madt + new_madt_size) {
+ pr_err("BPI: new_madt=%lx new_entry=%lx new_madt_size=%ld\n", (unsigned long)new_madt, (unsigned long)new_entry, new_madt_size);
panic("BPI: missing bytes while constructing new MADT\n");
}
if((void *)mcfg_entry != (void *)new_mcfg + new_mcfg_size) {
+ pr_err("BPI: new_mcfg=%lx mcfg_entry=%lx new_mcfg_size=%ld\n", (unsigned long)new_mcfg, (unsigned long)mcfg_entry, new_mcfg_size);
panic("BPI: missing bytes while constructing new MCFG\n");
}
new_madt->header.checksum = 0 - ext_listhdr_checksum((u8 *)new_madt, new_madt_size);
new_mcfg->header.checksum = 0 - ext_listhdr_checksum((u8 *)new_mcfg, new_mcfg_size);
+ print_hex_dump(KERN_INFO, "NEW MADT: ", DUMP_PREFIX_OFFSET, 16, 1, new_madt, new_madt_size, true);
+ print_hex_dump(KERN_INFO, "NEW MCFG: ", DUMP_PREFIX_OFFSET, 16, 1, new_mcfg, new_mcfg_size, true);
*new_table = (struct acpi_table_header *)new_madt;
// Override LS7A dma_node_id_offset
diff --git a/arch/loongarch/kernel/numa.c b/arch/loongarch/kernel/numa.c
index 5d45c389e961..11a7fbc7d52a 100644
--- a/arch/loongarch/kernel/numa.c
+++ b/arch/loongarch/kernel/numa.c
@@ -26,6 +26,8 @@
#include <asm/sections.h>
#include <asm/time.h>
+#include <uartout.h>
+
#include "legacy_boot.h"
int numa_off;
@@ -288,6 +290,9 @@ static void __init init_node_memblock(void)
mem_size = md->num_pages << EFI_PAGE_SHIFT;
mem_end = mem_start + mem_size;
+ pr_info("memDesc: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx Bytes\n",
+ mem_type, mem_start, mem_size);
+
switch (mem_type) {
case EFI_LOADER_CODE:
case EFI_LOADER_DATA:
@@ -371,21 +376,33 @@ int __init init_numa_memory(void)
if (WARN_ON(nodes_empty(node_possible_map)))
return -EINVAL;
+ loong_uart_puts("will_init_node_memblock\n");
init_node_memblock();
+ loong_uart_puts("done_init_node_memblock\n");
+ loong_uart_puts("will_bpi_init_node_memblock\n");
bpi_init_node_memblock(add_numamem_region);
+ loong_uart_puts("done_bpi_init_node_memblock\n");
+ loong_uart_puts("will_memblock_validate_numa_coverage\n");
if (!memblock_validate_numa_coverage(SZ_1M))
return -EINVAL;
+ loong_uart_puts("done_memblock_validate_numa_coverage\n");
for_each_node_mask(node, node_possible_map) {
+ loong_uart_puts("will_node_mem_init\n");
node_mem_init(node);
+ loong_uart_puts("will_node_set_online\n");
node_set_online(node);
+ loong_uart_puts("done_node_set_online\n");
}
+ loong_uart_puts("will_memblock_end_of_DRAM\n");
max_low_pfn = PHYS_PFN(memblock_end_of_DRAM());
+ loong_uart_puts("will_setup_nr_node_ids\n");
setup_nr_node_ids();
loongson_sysconf.nr_nodes = nr_node_ids;
loongson_sysconf.cores_per_node = cpumask_weight(&phys_cpus_on_node[0]);
+ loong_uart_puts("done_init_numa_memory\n");
return 0;
}
diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
index 7c8ba5f4834e..7ef540ca91bb 100644
--- a/arch/loongarch/kernel/setup.c
+++ b/arch/loongarch/kernel/setup.c
@@ -49,6 +49,8 @@
#include <asm/time.h>
#include <asm/unwind.h>
+#include <uartout.h>
+
#include "legacy_boot.h"
#define SMBIOS_BIOSSIZE_OFFSET 0x09
@@ -350,28 +352,45 @@ static void __init bootcmdline_init(char **cmdline_p)
void __init platform_init(void)
{
+ loong_uart_puts("will_reserve_vmcore!!\n");
arch_reserve_vmcore();
+ loong_uart_puts("will_reserve_carshker!!\n");
arch_reserve_crashkernel();
#ifdef CONFIG_ACPI_TABLE_UPGRADE
+ loong_uart_puts("will_acpi_table_upgrade!!\n");
acpi_table_upgrade();
#endif
+ loong_uart_puts("done_acpi_table_upgrade!!\n");
#ifdef CONFIG_ACPI
acpi_gbl_use_default_register_widths = false;
+ loong_uart_puts("will_acpi_boot_table_init!!\n");
acpi_boot_table_init();
+ loong_uart_puts("done_acpi_boot_table_init!!\n");
#endif
+ loong_uart_puts("will_fdt_scan_rsv_mem!!\n");
early_init_fdt_scan_reserved_mem();
+ loong_uart_puts("will_cpdt!!\n");
unflatten_and_copy_device_tree();
#ifdef CONFIG_NUMA
+ loong_uart_puts("will_init_numa_mem!!\n");
init_numa_memory();
#endif
+ loong_uart_puts("done_init_numa_mem!!\n");
+ loong_uart_puts("will_dmi_setup!!\n");
dmi_setup();
+ loong_uart_puts("will_smbios_parse!!\n");
smbios_parse();
+ loong_uart_puts("bios ver:");
+ loong_uart_puts(b_info.bios_version);
+ loong_uart_puts("\n");
pr_info("The BIOS Version: %s\n", b_info.bios_version);
+ loong_uart_puts("will_efi_runtime_init!!\n");
efi_runtime_init();
+ loong_uart_puts("done_platform_init!!\n");
}
static void __init check_kernel_sections_mem(void)
@@ -589,31 +608,49 @@ static void __init prefill_possible_map(void)
void __init setup_arch(char **cmdline_p)
{
+ loong_uart_puts("will_cpu_probe!!\n");
cpu_probe();
unwind_init();
+ loong_uart_puts("will_init_environ!!\n");
init_environ();
+ loong_uart_puts("will_efi_init!!\n");
efi_init();
+ loong_uart_puts("will_fdt_setup!!\n");
fdt_setup();
+ loong_uart_puts("will_bpi_init!!\n");
bpi_init();
+ loong_uart_puts("will_memblock_init!!\n");
memblock_init();
+ loong_uart_puts("will_pagetable_init!!\n");
pagetable_init();
+ loong_uart_puts("will_bootcmdline_init!!\n");
bootcmdline_init(cmdline_p);
+ loong_uart_puts("will_parse_early_param!!\n");
parse_early_param();
+ loong_uart_puts("will_reserve_initrd_mem!!\n");
reserve_initrd_mem();
+ loong_uart_puts("will_platform_init!!\n");
platform_init();
+ loong_uart_puts("will_arch_mem_init!!\n");
arch_mem_init(cmdline_p);
+ loong_uart_puts("will_resource_init!!\n");
resource_init();
+ loong_uart_puts("will_plat_smp_setup!!\n");
#ifdef CONFIG_SMP
plat_smp_setup();
+ loong_uart_puts("will_prefill_possible_map!!\n");
prefill_possible_map();
#endif
+ loong_uart_puts("will_paging_init!!\n");
paging_init();
+ loong_uart_puts("will_ksasn_init!!\n");
#ifdef CONFIG_KASAN
kasan_init();
#endif
+ loong_uart_puts("done_setup_arch!!\n");
}
diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c
index 16f5f9969bec..8a1cf8afd513 100644
--- a/arch/loongarch/kernel/smp.c
+++ b/arch/loongarch/kernel/smp.c
@@ -33,6 +33,8 @@
#include <asm/setup.h>
#include <asm/time.h>
+#include <uartout.h>
+
#include "legacy_boot.h"
int __cpu_number_map[NR_CPUS]; /* Map physical to logical */
@@ -285,15 +287,26 @@ static void __init fdt_smp_setup(void)
void __init loongson_smp_setup(void)
{
+ loong_uart_puts("will_fdt_smp_setup\n");
fdt_smp_setup();
+ loong_uart_puts("done_fdt_smp_setup\n");
+ static char __initdata buf[128] = {};
+ snprintf(buf, sizeof(buf), "loongson_sysconf.cores_per_package = %d\n", loongson_sysconf.cores_per_package);
+ loong_uart_puts(buf);
+ snprintf(buf, sizeof(buf), "loongson_sysconf.nr_cpus = %d\n", loongson_sysconf.nr_cpus);
+ loong_uart_puts(buf);
if (loongson_sysconf.cores_per_package == 0)
loongson_sysconf.cores_per_package = num_processors;
+ snprintf(buf, sizeof(buf), "cpu_logical_map(0)=%x\n", cpu_logical_map(0));
+ loong_uart_puts(buf);
cpu_data[0].core = cpu_logical_map(0) % loongson_sysconf.cores_per_package;
cpu_data[0].package = cpu_logical_map(0) / loongson_sysconf.cores_per_package;
+ loong_uart_puts("will_iocsr_write IPI_EN\n");
iocsr_write32(0xffffffff, LOONGARCH_IOCSR_IPI_EN);
+ loong_uart_puts("done_iocsr_write IPI_EN\n");
pr_info("Detected %i available CPU(s)\n", loongson_sysconf.nr_cpus);
}
diff --git a/drivers/firmware/efi/libstub/efi-stub-entry.c b/drivers/firmware/efi/libstub/efi-stub-entry.c
index a6c049835190..cadc8f8935e6 100644
--- a/drivers/firmware/efi/libstub/efi-stub-entry.c
+++ b/drivers/firmware/efi/libstub/efi-stub-entry.c
@@ -64,6 +64,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
efi_info("Booting Linux Kernel...\n");
+ efi_debug("image_addr=%p\n", (void *)image_addr);
status = handle_kernel_image(&image_addr, &image_size,
&reserve_addr,
&reserve_size,
@@ -72,6 +73,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
efi_err("Failed to relocate kernel\n");
return status;
}
+ efi_debug("after: image_addr=%p\n", (void *)image_addr);
screen_info_offset = image_addr - (unsigned long)image->image_base;
diff --git a/drivers/firmware/efi/libstub/loongarch.c b/drivers/firmware/efi/libstub/loongarch.c
index e0ae9c8550c3..2b1652d3c380 100644
--- a/drivers/firmware/efi/libstub/loongarch.c
+++ b/drivers/firmware/efi/libstub/loongarch.c
@@ -10,6 +10,8 @@
#include "efistub.h"
#include "loongarch-stub.h"
+#include <uartout.h>
+
typedef void __noreturn (*kernel_entry_t)(bool efi, unsigned long cmdline,
unsigned long systab);
@@ -44,6 +46,10 @@ static void detect_oldworld(void)
{
is_oldworld = !!(csr_read64(LOONGARCH_CSR_DMWIN1) & CSR_DMW1_PLV0);
efi_debug("is_oldworld: %d\n", is_oldworld);
+ efi_debug("dmwin0: %lx\n", csr_read64(LOONGARCH_CSR_DMWIN0));
+ efi_debug("dmwin1: %lx\n", csr_read64(LOONGARCH_CSR_DMWIN1));
+ efi_debug("dmwin2: %lx\n", csr_read64(LOONGARCH_CSR_DMWIN2));
+ efi_debug("dmwin3: %lx\n", csr_read64(LOONGARCH_CSR_DMWIN3));
if(is_oldworld) {
efi_info("Booting on OldWorld firmware\n");
}
@@ -72,6 +78,10 @@ efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image,
return status;
}
+ efi_debug("kernel_addr=%p\n", (void *)kernel_addr);
+ efi_debug("image=%p\n", image);
+ efi_debug("real_kernel_entry=%p\n", (void *)kernel_entry_address(kernel_addr, image));
+ efi_debug("*(kernel_addr + 8)=%p\n", *(void **)(kernel_addr + 8));
efi_info("Exiting boot services\n");
efi_novamap = false;
diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c
index 1ceace956758..af1fb2f74149 100644
--- a/drivers/firmware/efi/libstub/zboot.c
+++ b/drivers/firmware/efi/libstub/zboot.c
@@ -72,6 +72,7 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
int ret;
WRITE_ONCE(efi_system_table, systab);
+ efi_debug("efi_system_table=%p\n", efi_system_table);
free_mem_ptr = (unsigned long)&zboot_heap;
free_mem_end_ptr = free_mem_ptr + sizeof(zboot_heap);
@@ -82,6 +83,7 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
error("Failed to locate parent's loaded image protocol");
return status;
}
+ efi_debug("image=%p\n", image);
status = efi_handle_cmdline(image, &cmdline_ptr);
if (status != EFI_SUCCESS)
@@ -96,6 +98,7 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
// If the architecture has a preferred address for the image,
// try that first.
image_base = alloc_preferred_address(alloc_size);
+ efi_debug("image_base=%p\n", (void *)image_base);
if (image_base == ULONG_MAX) {
unsigned long min_kimg_align = efi_get_kimg_min_align();
u32 seed = U32_MAX;
@@ -124,9 +127,11 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
efi_err("Failed to allocate memory\n");
goto free_cmdline;
}
+ efi_debug("2:image_base=%p\n", (void *)image_base);
}
// Decompress the payload into the newly allocated buffer.
+ efi_debug("_gzdata_start=%p\n", _gzdata_start);
ret = __decompress(_gzdata_start, compressed_size, NULL, NULL,
(void *)image_base, alloc_size, NULL, error);
if (ret < 0) {
diff --git a/init/main.c b/init/main.c
index 5dcf5274c09c..768537a5efcf 100644
--- a/init/main.c
+++ b/init/main.c
@@ -109,6 +109,8 @@
#include <asm/sections.h>
#include <asm/cacheflush.h>
+#include <uartout.h>
+
#define CREATE_TRACE_POINTS
#include <trace/events/initcall.h>
@@ -750,6 +752,9 @@ static int __init do_early_param(char *param, char *val,
(strcmp(param, "console") == 0 &&
strcmp(p->str, "earlycon") == 0)
) {
+ loong_uart_puts("will_do_early_param: ");
+ loong_uart_puts(param);
+ loong_uart_puts("\n");
if (p->setup_func(val) != 0)
pr_warn("Malformed early option '%s'\n", param);
}
@@ -884,6 +889,8 @@ void start_kernel(void)
char *command_line;
char *after_dashes;
+ loong_uart_puts("start_kernel!!\n");
+
set_task_stack_end_magic(&init_task);
smp_setup_processor_id();
debug_objects_early_init();
@@ -902,14 +909,22 @@ void start_kernel(void)
page_address_init();
pr_notice("%s", linux_banner);
early_security_init();
+ loong_uart_puts("will_setup_arch!!\n");
setup_arch(&command_line);
+ loong_uart_puts("will_setup_boot_config!!\n");
setup_boot_config();
+ loong_uart_puts("will_setup_command_line!!\n");
setup_command_line(command_line);
+ loong_uart_puts("will_setup_nr_cpu_ids!!\n");
setup_nr_cpu_ids();
+ loong_uart_puts("will_setup_per_cpu_areas!!\n");
setup_per_cpu_areas();
+ loong_uart_puts("will_prepare_boot_cpu!!\n");
smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
+ loong_uart_puts("will_boot_cpu_hp_init!!\n");
boot_cpu_hotplug_init();
+ loong_uart_puts("will_print_cmdline!!\n");
pr_notice("Kernel command line: %s\n", saved_command_line);
/* parameters may set static keys */
jump_label_init();
--
2.43.0
From daa2d6b75435da1c98be4c4314913fa411dec59e Mon Sep 17 00:00:00 2001
From: Huacai Chen <[email protected]>
Date: Tue, 23 Jul 2024 14:45:08 +0800
Subject: [PATCH 10/11] irqchip/loongarch-cpu: Fix return value of
lpic_gsi_to_irq()
lpic_gsi_to_irq() should return a valid irq if acpi_register_gsi()
succeed, and return 0 otherwise. But now lpic_gsi_to_irq() converts
a negative return value of acpi_register_gsi() to a positive value
silently, so fix it.
Reported-by: Miao Wang <[email protected]>
Signed-off-by: Huacai Chen <[email protected]>
---
drivers/irqchip/irq-loongarch-cpu.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/irqchip/irq-loongarch-cpu.c b/drivers/irqchip/irq-loongarch-cpu.c
index 9d8f2c406043..b35903a06902 100644
--- a/drivers/irqchip/irq-loongarch-cpu.c
+++ b/drivers/irqchip/irq-loongarch-cpu.c
@@ -18,11 +18,13 @@ struct fwnode_handle *cpuintc_handle;
static u32 lpic_gsi_to_irq(u32 gsi)
{
+ int irq = 0;
+
/* Only pch irqdomain transferring is required for LoongArch. */
if (gsi >= GSI_MIN_PCH_IRQ && gsi <= GSI_MAX_PCH_IRQ)
- return acpi_register_gsi(NULL, gsi, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_HIGH);
+ irq = acpi_register_gsi(NULL, gsi, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_HIGH);
- return 0;
+ return (irq > 0) ? irq : 0;
}
static struct fwnode_handle *lpic_get_gsi_domain_id(u32 gsi)
--
2.43.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment