LoongArch: Add FDT booting support from efi system table

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>
This commit is contained in:
Binbin Zhou 2022-12-10 22:40:05 +08:00 committed by Huacai Chen
parent a275a82dcd
commit 88d4d957ed
10 changed files with 145 additions and 7 deletions

View 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

View 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 */

View 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);

View 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

View 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()) {

View 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;

View 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;

View 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();

View 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;

View 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));