LoongArch: Add FDT booting support from efi system table
authorBinbin Zhou <zhoubinbin@loongson.cn>
Sat, 10 Dec 2022 14:40:05 +0000 (22:40 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Wed, 14 Dec 2022 00:41:53 +0000 (08:41 +0800)
Since commit 40cd01a9c324("efi/loongarch: libstub: remove dependency on
flattened DT"), we can parse the FDT from efi system table.

And now, LoongArch is coming to support booting with FDT, so we add the
relevant booting support as well as parameter parsing.

Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
arch/loongarch/Kconfig
arch/loongarch/include/asm/efi.h
arch/loongarch/include/asm/setup.h
arch/loongarch/kernel/acpi.c
arch/loongarch/kernel/efi.c
arch/loongarch/kernel/env.c
arch/loongarch/kernel/numa.c
arch/loongarch/kernel/setup.c
arch/loongarch/kernel/smp.c
arch/loongarch/pci/acpi.c

index 0daf6263655b396a36159fa9c72d361fd10fda4a..48db4b27b9afa36f3c368aa9a67d9bd646cd91c0 100644 (file)
@@ -111,6 +111,8 @@ config LOONGARCH
        select MODULES_USE_ELF_RELA if MODULES
        select NEED_PER_CPU_EMBED_FIRST_CHUNK
        select NEED_PER_CPU_PAGE_FIRST_CHUNK
+       select OF
+       select OF_EARLY_FLATTREE
        select PCI
        select PCI_DOMAINS_GENERIC
        select PCI_ECAM if ACPI
index 174567b00ddb907d32241ae45a7d71ff2e902050..81e5d33718684a42bfe51524eef89e33791c8d6c 100644 (file)
@@ -9,6 +9,7 @@
 
 void __init efi_init(void);
 void __init efi_runtime_init(void);
+void __init *efi_fdt_pointer(void);
 void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
 
 #define ARCH_EFI_IRQ_FLAGS_MASK  0x00000004  /* Bit 2: CSR.CRMD.IE */
index ca373f8e3c4db29a42fccdcca72a816135ea286c..72ead58039f3e159ae13c7e066c4ee9793aa2208 100644 (file)
@@ -13,6 +13,7 @@
 
 extern unsigned long eentry;
 extern unsigned long tlbrentry;
+extern char init_command_line[COMMAND_LINE_SIZE];
 extern void tlb_init(int cpu);
 extern void cpu_cache_init(void);
 extern void cache_error_setup(void);
index 8319cc40900908fb2c88ae28ef094afaf9464641..5a63f85f5798411df36d24a53dbcc142e81b62c6 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
 #include <linux/memblock.h>
+#include <linux/of_fdt.h>
 #include <linux/serial_core.h>
 #include <asm/io.h>
 #include <asm/numa.h>
@@ -145,14 +146,14 @@ void __init acpi_boot_table_init(void)
         * If acpi_disabled, bail out
         */
        if (acpi_disabled)
-               return;
+               goto fdt_earlycon;
 
        /*
         * Initialize the ACPI boot-time table parser.
         */
        if (acpi_table_init()) {
                disable_acpi();
-               return;
+               goto fdt_earlycon;
        }
 
        loongson_sysconf.boot_cpu_id = read_csr_cpuid();
@@ -164,6 +165,12 @@ void __init acpi_boot_table_init(void)
 
        /* Do not enable ACPI SPCR console by default */
        acpi_parse_spcr(earlycon_acpi_spcr_enable, false);
+
+       return;
+
+fdt_earlycon:
+       if (earlycon_acpi_spcr_enable)
+               early_init_dt_scan_chosen_stdout();
 }
 
 #ifdef CONFIG_ACPI_NUMA
index a31329971133946d383fc16fc2eaf99d78f0bcbb..ea485b0e1e7f5dda5666183205182ad96ed069bd 100644 (file)
@@ -28,16 +28,29 @@ static unsigned long efi_nr_tables;
 static unsigned long efi_config_table;
 
 static unsigned long __initdata boot_memmap = EFI_INVALID_TABLE_ADDR;
+static unsigned long __initdata fdt_pointer = EFI_INVALID_TABLE_ADDR;
 
 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" },
        {},
 };
 
+void __init *efi_fdt_pointer(void)
+{
+       if (!efi_systab)
+               return NULL;
+
+       if (fdt_pointer == EFI_INVALID_TABLE_ADDR)
+               return NULL;
+
+       return early_memremap_ro(fdt_pointer, SZ_64K);
+}
+
 void __init efi_runtime_init(void)
 {
-       if (!efi_enabled(EFI_BOOT))
+       if (!efi_enabled(EFI_BOOT) || !efi_systab->runtime)
                return;
 
        if (efi_runtime_disabled()) {
index 6d56a463b091c0f6069380565ea6e0883e7571a6..6b3bfb0092e60b34946490415ff7cd2a51287886 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/early_ioremap.h>
 #include <asm/bootinfo.h>
 #include <asm/loongson.h>
+#include <asm/setup.h>
 
 u64 efi_system_table;
 struct loongson_system_configuration loongson_sysconf;
@@ -27,6 +28,7 @@ void __init init_environ(void)
                clear_bit(EFI_BOOT, &efi.flags);
 
        strscpy(boot_command_line, cmdline, COMMAND_LINE_SIZE);
+       strscpy(init_command_line, cmdline, COMMAND_LINE_SIZE);
        early_memunmap(cmdline, COMMAND_LINE_SIZE);
 
        efi_system_table = fw_arg2;
index a13f92593cfdad89294abe8d37582b40c2c12954..3019ca14c760b59fe55740352911f3975c5918bb 100644 (file)
@@ -388,6 +388,21 @@ static void __init numa_default_distance(void)
        }
 }
 
+/*
+ * fake_numa_init() - For Non-ACPI systems
+ * Return: 0 on success, -errno on failure.
+ */
+static int __init fake_numa_init(void)
+{
+       phys_addr_t start = memblock_start_of_DRAM();
+       phys_addr_t end = memblock_end_of_DRAM() - 1;
+
+       node_set(0, numa_nodes_parsed);
+       pr_info("Faking a node at [mem %pap-%pap]\n", &start, &end);
+
+       return numa_add_memblk(0, start, end + 1);
+}
+
 int __init init_numa_memory(void)
 {
        int i;
@@ -404,7 +419,7 @@ int __init init_numa_memory(void)
        memset(&numa_meminfo, 0, sizeof(numa_meminfo));
 
        /* Parse SRAT and SLIT if provided by firmware. */
-       ret = acpi_numa_init();
+       ret = acpi_disabled ? fake_numa_init() : acpi_numa_init();
        if (ret < 0)
                return ret;
 
index 53831bcb11ca36abb5dd450e6f3717cacff72c2d..f9f5a130710ca29409c6b3823dc28a344c0c6d9a 100644 (file)
@@ -28,6 +28,9 @@
 #include <linux/sizes.h>
 #include <linux/device.h>
 #include <linux/dma-map-ops.h>
+#include <linux/libfdt.h>
+#include <linux/of_fdt.h>
+#include <linux/of_address.h>
 #include <linux/swiotlb.h>
 
 #include <asm/addrspace.h>
@@ -69,6 +72,7 @@ static const char dmi_empty_string[] = "        ";
  *
  * These are initialized so they are in the .data section
  */
+char init_command_line[COMMAND_LINE_SIZE] __initdata;
 
 static int num_standard_resources;
 static struct resource *standard_resources;
@@ -253,6 +257,58 @@ static void __init arch_parse_crashkernel(void)
 #endif
 }
 
+static void __init fdt_setup(void)
+{
+#ifdef CONFIG_OF_EARLY_FLATTREE
+       void *fdt_pointer;
+
+       /* ACPI-based systems do not require parsing fdt */
+       if (acpi_os_get_root_pointer())
+               return;
+
+       /* Look for a device tree configuration table entry */
+       fdt_pointer = efi_fdt_pointer();
+       if (!fdt_pointer || fdt_check_header(fdt_pointer))
+               return;
+
+       early_init_dt_scan(fdt_pointer);
+       early_init_fdt_reserve_self();
+
+       max_low_pfn = PFN_PHYS(memblock_end_of_DRAM());
+#endif
+}
+
+static void __init bootcmdline_init(char **cmdline_p)
+{
+       /*
+        * If CONFIG_CMDLINE_FORCE is enabled then initializing the command line
+        * is trivial - we simply use the built-in command line unconditionally &
+        * unmodified.
+        */
+       if (IS_ENABLED(CONFIG_CMDLINE_FORCE)) {
+               strscpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
+               goto out;
+       }
+
+#ifdef CONFIG_OF_FLATTREE
+       /*
+        * If CONFIG_CMDLINE_BOOTLOADER is enabled and we are in FDT-based system,
+        * the boot_command_line will be overwritten by early_init_dt_scan_chosen().
+        * So we need to append init_command_line (the original copy of boot_command_line)
+        * to boot_command_line.
+        */
+       if (initial_boot_params) {
+               if (boot_command_line[0])
+                       strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
+
+               strlcat(boot_command_line, init_command_line, COMMAND_LINE_SIZE);
+       }
+#endif
+
+out:
+       *cmdline_p = boot_command_line;
+}
+
 void __init platform_init(void)
 {
        arch_reserve_vmcore();
@@ -265,6 +321,7 @@ void __init platform_init(void)
        acpi_gbl_use_default_register_widths = false;
        acpi_boot_table_init();
 #endif
+       unflatten_and_copy_device_tree();
 
 #ifdef CONFIG_NUMA
        init_numa_memory();
@@ -297,6 +354,8 @@ static void __init arch_mem_init(char **cmdline_p)
 
        check_kernel_sections_mem();
 
+       early_init_fdt_scan_reserved_mem();
+
        /*
         * In order to reduce the possibility of kernel panic when failed to
         * get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate
@@ -422,12 +481,13 @@ static void __init prefill_possible_map(void)
 void __init setup_arch(char **cmdline_p)
 {
        cpu_probe();
-       *cmdline_p = boot_command_line;
 
        init_environ();
        efi_init();
+       fdt_setup();
        memblock_init();
        pagetable_init();
+       bootcmdline_init(cmdline_p);
        parse_early_param();
        reserve_initrd_mem();
 
index 14508d429ffa32b4bc6951d2d1d1ad352cd540e8..b78816cf74ae51518bf64fb303a08ee9da5579a2 100644 (file)
@@ -180,8 +180,42 @@ irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
        return IRQ_HANDLED;
 }
 
+static void __init fdt_smp_setup(void)
+{
+#ifdef CONFIG_OF
+       unsigned int cpu, cpuid;
+       struct device_node *node = NULL;
+
+       for_each_of_cpu_node(node) {
+               if (!of_device_is_available(node))
+                       continue;
+
+               cpuid = of_get_cpu_hwid(node, 0);
+               if (cpuid >= nr_cpu_ids)
+                       continue;
+
+               if (cpuid == loongson_sysconf.boot_cpu_id) {
+                       cpu = 0;
+                       numa_add_cpu(cpu);
+               } else {
+                       cpu = cpumask_next_zero(-1, cpu_present_mask);
+               }
+
+               num_processors++;
+               set_cpu_possible(cpu, true);
+               set_cpu_present(cpu, true);
+               __cpu_number_map[cpuid] = cpu;
+               __cpu_logical_map[cpu] = cpuid;
+       }
+
+       loongson_sysconf.nr_cpus = num_processors;
+#endif
+}
+
 void __init loongson_smp_setup(void)
 {
+       fdt_smp_setup();
+
        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;
 
index 8235ec92b41fe2b35b66848447a94698d3aaeb04..365f7de771cbb9e6c72d1d8d0133af476510c2a0 100644 (file)
@@ -26,9 +26,12 @@ void pcibios_add_bus(struct pci_bus *bus)
 
 int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
 {
-       struct pci_config_window *cfg = bridge->bus->sysdata;
-       struct acpi_device *adev = to_acpi_device(cfg->parent);
+       struct acpi_device *adev = NULL;
        struct device *bus_dev = &bridge->bus->dev;
+       struct pci_config_window *cfg = bridge->bus->sysdata;
+
+       if (!acpi_disabled)
+               adev = to_acpi_device(cfg->parent);
 
        ACPI_COMPANION_SET(&bridge->dev, adev);
        set_dev_node(bus_dev, pa_to_nid(cfg->res.start));