> On Sun, Feb 16, 2014 at 04:01:22PM +0800, Huacai Chen wrote: >> The new UEFI-like firmware interface (LEFI, i.e. Loongson Unified >> Firmware Interface) has 3 advantages: >> >> 1, Firmware export a physical memory map which is similar to X86's >> E820 map, so prom_init_memory() will be more elegant that #ifdef >> clauses can be removed. >> 2, Firmware export a pci irq routing table, we no longer need pci >> irq routing fixup in kernel's code. >> 3, Firmware has a built-in vga bios, and its address is exported, >> the linux kernel no longer need an embedded blob. >> >> With the LEFI interface, Loongson-3A/2G and all their successors can use >> a unified kernel. All Loongson-based machines support this new interface >> except 2E/2F series. >> >> Signed-off-by: Huacai Chen <chenhc@xxxxxxxxxx> >> Signed-off-by: Hongliang Tao <taohl@xxxxxxxxxx> >> Signed-off-by: Hua Yan <yanh@xxxxxxxxxx> >> Tested-by: Alex Smith <alex.smith@xxxxxxxxxx> >> Reviewed-by: Alex Smith <alex.smith@xxxxxxxxxx> >> --- >> arch/mips/include/asm/mach-loongson/boot_param.h | 163 >> ++++++++++++++++++++++ >> arch/mips/include/asm/mach-loongson/loongson.h | 4 +- >> arch/mips/loongson/common/env.c | 67 +++++++-- >> arch/mips/loongson/common/init.c | 9 +- >> arch/mips/loongson/common/mem.c | 42 ++++++ >> arch/mips/loongson/common/pci.c | 6 +- >> arch/mips/loongson/common/reset.c | 21 +++ >> 7 files changed, 292 insertions(+), 20 deletions(-) >> create mode 100644 arch/mips/include/asm/mach-loongson/boot_param.h >> >> diff --git a/arch/mips/include/asm/mach-loongson/boot_param.h >> b/arch/mips/include/asm/mach-loongson/boot_param.h >> new file mode 100644 >> index 0000000..829a7ec >> --- /dev/null >> +++ b/arch/mips/include/asm/mach-loongson/boot_param.h >> @@ -0,0 +1,163 @@ >> +#ifndef __ASM_MACH_LOONGSON_BOOT_PARAM_H_ >> +#define __ASM_MACH_LOONGSON_BOOT_PARAM_H_ >> + >> +#define SYSTEM_RAM_LOW 1 >> +#define SYSTEM_RAM_HIGH 2 >> +#define MEM_RESERVED 3 >> +#define PCI_IO 4 >> +#define PCI_MEM 5 >> +#define LOONGSON_CFG_REG 6 >> +#define VIDEO_ROM 7 >> +#define ADAPTER_ROM 8 >> +#define ACPI_TABLE 9 >> +#define MAX_MEMORY_TYPE 10 >> + >> +#define LOONGSON3_BOOT_MEM_MAP_MAX 128 >> +struct efi_memory_map_loongson { >> + u16 vers; /* version of efi_memory_map */ >> + u32 nr_map; /* number of memory_maps */ >> + u32 mem_freq; /* memory frequence */ >> + struct mem_map { >> + u32 node_id; /* node_id which memory attached to */ >> + u32 mem_type; /* system memory, pci memory, pci io, etc. */ >> + u64 mem_start; /* memory map start address */ >> + u32 mem_size; /* each memory_map size, not the total size */ >> + } map[LOONGSON3_BOOT_MEM_MAP_MAX]; >> +} __packed; >> + >> +enum loongson_cpu_type { >> + Loongson_2E = 0, >> + Loongson_2F = 1, >> + Loongson_3A = 2, >> + Loongson_3B = 3, >> + Loongson_1A = 4, >> + Loongson_1B = 5 >> +}; >> + >> +/* >> + * Capability and feature descriptor structure for MIPS CPU >> + */ >> +struct efi_cpuinfo_loongson { >> + u16 vers; /* version of efi_cpuinfo_loongson */ >> + u32 processor_id; /* PRID, e.g. 6305, 6306 */ >> + u32 cputype; /* Loongson_3A/3B, etc. */ >> + u32 total_node; /* num of total numa nodes */ >> + u32 cpu_startup_core_id; /* Core id */ >> + u32 cpu_clock_freq; /* cpu_clock */ >> + u32 nr_cpus; >> +} __packed; >> + >> +struct system_loongson { >> + u16 vers; /* version of system_loongson */ >> + u32 ccnuma_smp; /* 0: no numa; 1: has numa */ >> + u32 sing_double_channel; /* 1:single; 2:double */ >> +} __packed; >> + >> +struct irq_source_routing_table { >> + u16 vers; >> + u16 size; >> + u16 rtr_bus; >> + u16 rtr_devfn; >> + u32 vendor; >> + u32 device; >> + u32 PIC_type; /* conform use HT or PCI to route to CPU-PIC */ >> + u64 ht_int_bit; /* 3A: 1<<24; 3B: 1<<16 */ >> + u64 ht_enable; /* irqs used in this PIC */ >> + u32 node_id; /* node id: 0x0-0; 0x1-1; 0x10-2; 0x11-3 */ >> + u64 pci_mem_start_addr; >> + u64 pci_mem_end_addr; >> + u64 pci_io_start_addr; >> + u64 pci_io_end_addr; >> + u64 pci_config_addr; >> + u32 dma_mask_bits; >> +} __packed; >> + >> +struct interface_info { >> + u16 vers; /* version of the specificition */ >> + u16 size; >> + u8 flag; >> + char description[64]; >> +} __packed; >> + >> +#define MAX_RESOURCE_NUMBER 128 >> +struct resource_loongson { >> + u64 start; /* resource start address */ >> + u64 end; /* resource end address */ >> + char name[64]; >> + u32 flags; >> +}; >> + >> +struct archdev_data {}; /* arch specific additions */ >> + >> +struct board_devices { >> + char name[64]; /* hold the device name */ >> + u32 num_resources; /* number of device_resource */ >> + /* for each device's resource */ >> + struct resource_loongson resource[MAX_RESOURCE_NUMBER]; >> + /* arch specific additions */ >> + struct archdev_data archdata; >> +}; >> + >> +struct loongson_special_attribute { >> + u16 vers; /* version of this special */ >> + char special_name[64]; /* special_atribute_name */ >> + u32 loongson_special_type; /* type of special device */ >> + /* for each device's resource */ >> + struct resource_loongson resource[MAX_RESOURCE_NUMBER]; >> +}; >> + >> +struct loongson_params { >> + u64 memory_offset; /* efi_memory_map_loongson struct offset */ >> + u64 cpu_offset; /* efi_cpuinfo_loongson struct offset */ >> + u64 system_offset; /* system_loongson struct offset */ >> + u64 irq_offset; /* irq_source_routing_table struct offset */ >> + u64 interface_offset; /* interface_info struct offset */ >> + u64 special_offset; /* loongson_special_attribute struct offset */ >> + u64 boarddev_table_offset; /* board_devices offset */ >> +}; >> + >> +struct smbios_tables { >> + u16 vers; /* version of smbios */ >> + u64 vga_bios; /* vga_bios address */ >> + struct loongson_params lp; >> +}; >> + >> +struct efi_reset_system_t { >> + u64 ResetCold; >> + u64 ResetWarm; >> + u64 ResetType; >> + u64 Shutdown; >> + u64 DoSuspend; /* NULL if not support */ >> +}; >> + >> +struct efi_loongson { >> + u64 mps; /* MPS table */ >> + u64 acpi; /* ACPI table (IA64 ext 0.71) */ >> + u64 acpi20; /* ACPI table (ACPI 2.0) */ >> + struct smbios_tables smbios; /* SM BIOS table */ >> + u64 sal_systab; /* SAL system table */ >> + u64 boot_info; /* boot info table */ >> +}; >> + >> +struct boot_params { >> + struct efi_loongson efi; >> + struct efi_reset_system_t reset_system; >> +}; >> + >> +struct loongson_system_configuration { >> + u32 nr_cpus; >> + enum loongson_cpu_type cputype; >> + u64 ht_control_base; >> + u64 pci_mem_start_addr; >> + u64 pci_mem_end_addr; >> + u64 pci_io_base; >> + u64 restart_addr; >> + u64 poweroff_addr; >> + u64 suspend_addr; >> + u64 vgabios_addr; >> + u32 dma_mask_bits; >> +}; >> + >> +extern struct efi_memory_map_loongson *loongson_memmap; >> +extern struct loongson_system_configuration loongson_sysconf; >> +#endif >> diff --git a/arch/mips/include/asm/mach-loongson/loongson.h >> b/arch/mips/include/asm/mach-loongson/loongson.h >> index b286534..5913ea0 100644 >> --- a/arch/mips/include/asm/mach-loongson/loongson.h >> +++ b/arch/mips/include/asm/mach-loongson/loongson.h >> @@ -24,8 +24,8 @@ extern void mach_prepare_reboot(void); >> extern void mach_prepare_shutdown(void); >> >> /* environment arguments from bootloader */ >> -extern unsigned long cpu_clock_freq; >> -extern unsigned long memsize, highmemsize; >> +extern u32 cpu_clock_freq; >> +extern u32 memsize, highmemsize; >> >> /* loongson-specific command line, env and memory initialization */ >> extern void __init prom_init_memory(void); >> diff --git a/arch/mips/loongson/common/env.c >> b/arch/mips/loongson/common/env.c >> index 0a18fcf..0c543ea 100644 >> --- a/arch/mips/loongson/common/env.c >> +++ b/arch/mips/loongson/common/env.c >> @@ -18,29 +18,30 @@ >> * option) any later version. >> */ >> #include <linux/module.h> >> - >> #include <asm/bootinfo.h> >> - >> #include <loongson.h> >> +#include <boot_param.h> >> >> -unsigned long cpu_clock_freq; >> +u32 cpu_clock_freq; >> EXPORT_SYMBOL(cpu_clock_freq); >> -unsigned long memsize, highmemsize; >> +struct efi_memory_map_loongson *loongson_memmap; >> +struct loongson_system_configuration loongson_sysconf; >> >> #define parse_even_earlier(res, option, p) \ >> do { \ >> unsigned int tmp __maybe_unused; \ >> \ >> if (strncmp(option, (char *)p, strlen(option)) == 0) \ >> - tmp = strict_strtol((char *)p + strlen(option"="), 10, &res); \ >> + tmp = kstrtou32((char *)p + strlen(option"="), 10, &res); \ >> } while (0) >> >> void __init prom_init_env(void) >> { >> /* pmon passes arguments in 32bit pointers */ >> - int *_prom_envp; >> - unsigned long bus_clock; >> unsigned int processor_id; >> + >> +#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE >> + int *_prom_envp; >> long l; >> >> /* firmware arguments are initialized in head.S */ >> @@ -48,7 +49,6 @@ void __init prom_init_env(void) >> >> l = (long)*_prom_envp; >> while (l != 0) { >> - parse_even_earlier(bus_clock, "busclock", l); >> parse_even_earlier(cpu_clock_freq, "cpuclock", l); >> parse_even_earlier(memsize, "memsize", l); >> parse_even_earlier(highmemsize, "highmemsize", l); >> @@ -57,8 +57,48 @@ void __init prom_init_env(void) >> } >> if (memsize == 0) >> memsize = 256; >> - if (bus_clock == 0) >> - bus_clock = 66000000; >> + pr_info("memsize=%u, highmemsize=%u\n", memsize, highmemsize); >> +#else >> + struct boot_params *boot_p; >> + struct loongson_params *loongson_p; >> + struct efi_cpuinfo_loongson *ecpu; >> + struct irq_source_routing_table *eirq_source; >> + >> + /* firmware arguments are initialized in head.S */ >> + boot_p = (struct boot_params *)fw_arg2; >> + loongson_p = &(boot_p->efi.smbios.lp); >> + >> + ecpu = (struct efi_cpuinfo_loongson *) >> + ((u64)loongson_p + loongson_p->cpu_offset); >> + eirq_source = (struct irq_source_routing_table *) >> + ((u64)loongson_p + loongson_p->irq_offset); >> + loongson_memmap = (struct efi_memory_map_loongson *) >> + ((u64)loongson_p + loongson_p->memory_offset); >> + >> + cpu_clock_freq = ecpu->cpu_clock_freq; >> + loongson_sysconf.cputype = ecpu->cputype; >> + loongson_sysconf.nr_cpus = ecpu->nr_cpus; >> + if (ecpu->nr_cpus > NR_CPUS || ecpu->nr_cpus == 0) >> + loongson_sysconf.nr_cpus = NR_CPUS; >> + >> + loongson_sysconf.pci_mem_start_addr = eirq_source->pci_mem_start_addr; >> + loongson_sysconf.pci_mem_end_addr = eirq_source->pci_mem_end_addr; >> + loongson_sysconf.pci_io_base = eirq_source->pci_io_start_addr; >> + loongson_sysconf.dma_mask_bits = eirq_source->dma_mask_bits; >> + if (loongson_sysconf.dma_mask_bits < 32 || >> + loongson_sysconf.dma_mask_bits > 64) >> + loongson_sysconf.dma_mask_bits = 32; > > I guess the tests are for machines which do not export dma_mask_bits. Are > we sure that on such machine, the value at this memory location can not > be in between 32 and 64? I'm sure that there aren't invalid value between 32 and 64. > >> + >> + loongson_sysconf.restart_addr = boot_p->reset_system.ResetWarm; >> + loongson_sysconf.poweroff_addr = boot_p->reset_system.Shutdown; >> + loongson_sysconf.suspend_addr = boot_p->reset_system.DoSuspend; >> + >> + loongson_sysconf.ht_control_base = 0x90000EFDFB000000; >> + loongson_sysconf.vgabios_addr = boot_p->efi.smbios.vga_bios; >> + pr_debug("Shutdown Addr: %llx, Restart Addr: %llx, VBIOS Addr: >> %llx\n", >> + loongson_sysconf.poweroff_addr, loongson_sysconf.restart_addr, >> + loongson_sysconf.vgabios_addr); >> +#endif >> if (cpu_clock_freq == 0) { >> processor_id = (¤t_cpu_data)->processor_id; >> switch (processor_id & PRID_REV_MASK) { >> @@ -68,12 +108,13 @@ void __init prom_init_env(void) >> case PRID_REV_LOONGSON2F: >> cpu_clock_freq = 797000000; >> break; >> + case PRID_REV_LOONGSON3A: >> + cpu_clock_freq = 900000000; >> + break; >> default: >> cpu_clock_freq = 100000000; >> break; >> } >> } >> - >> - pr_info("busclock=%ld, cpuclock=%ld, memsize=%ld, highmemsize=%ld\n", >> - bus_clock, cpu_clock_freq, memsize, highmemsize); >> + pr_info("CpuClock = %u\n", cpu_clock_freq); >> } >> diff --git a/arch/mips/loongson/common/init.c >> b/arch/mips/loongson/common/init.c >> index ae7af1f..81ba3b4 100644 >> --- a/arch/mips/loongson/common/init.c >> +++ b/arch/mips/loongson/common/init.c >> @@ -17,10 +17,6 @@ unsigned long __maybe_unused >> _loongson_addrwincfg_base; >> >> void __init prom_init(void) >> { >> - /* init base address of io space */ >> - set_io_port_base((unsigned long) >> - ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE)); >> - >> #ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG >> _loongson_addrwincfg_base = (unsigned long) >> ioremap(LOONGSON_ADDRWINCFG_BASE, LOONGSON_ADDRWINCFG_SIZE); >> @@ -28,6 +24,11 @@ void __init prom_init(void) >> >> prom_init_cmdline(); >> prom_init_env(); >> + >> + /* init base address of io space */ >> + set_io_port_base((unsigned long) >> + ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE)); >> + >> prom_init_memory(); >> >> /*init the uart base address */ >> diff --git a/arch/mips/loongson/common/mem.c >> b/arch/mips/loongson/common/mem.c >> index 8626a42..b01d524 100644 >> --- a/arch/mips/loongson/common/mem.c >> +++ b/arch/mips/loongson/common/mem.c >> @@ -11,9 +11,14 @@ >> #include <asm/bootinfo.h> >> >> #include <loongson.h> >> +#include <boot_param.h> >> #include <mem.h> >> #include <pci.h> >> >> +#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE >> + >> +u32 memsize, highmemsize; >> + >> void __init prom_init_memory(void) >> { >> add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM); >> @@ -49,6 +54,43 @@ void __init prom_init_memory(void) >> #endif /* !CONFIG_64BIT */ >> } >> >> +#else /* CONFIG_LEFI_FIRMWARE_INTERFACE */ >> + >> +void __init prom_init_memory(void) >> +{ >> + int i; >> + u32 node_id; >> + u32 mem_type; >> + >> + /* parse memory information */ >> + for (i = 0; i < loongson_memmap->nr_map; i++) { >> + node_id = loongson_memmap->map[i].node_id; >> + mem_type = loongson_memmap->map[i].mem_type; >> + >> + if (node_id == 0) { >> + switch (mem_type) { >> + case SYSTEM_RAM_LOW: >> + add_memory_region(loongson_memmap->map[i].mem_start, >> + (u64)loongson_memmap->map[i].mem_size << 20, >> + BOOT_MEM_RAM); >> + break; >> + case SYSTEM_RAM_HIGH: >> + add_memory_region(loongson_memmap->map[i].mem_start, >> + (u64)loongson_memmap->map[i].mem_size << 20, >> + BOOT_MEM_RAM); >> + break; >> + case MEM_RESERVED: >> + add_memory_region(loongson_memmap->map[i].mem_start, >> + (u64)loongson_memmap->map[i].mem_size << 20, >> + BOOT_MEM_RESERVED); >> + break; >> + } >> + } >> + } >> +} >> + >> +#endif /* CONFIG_LEFI_FIRMWARE_INTERFACE */ >> + >> /* override of arch/mips/mm/cache.c: __uncached_access */ >> int __uncached_access(struct file *file, unsigned long addr) >> { >> diff --git a/arch/mips/loongson/common/pci.c >> b/arch/mips/loongson/common/pci.c >> index fa77844..003ab4e 100644 >> --- a/arch/mips/loongson/common/pci.c >> +++ b/arch/mips/loongson/common/pci.c >> @@ -11,6 +11,7 @@ >> >> #include <pci.h> >> #include <loongson.h> >> +#include <boot_param.h> >> >> static struct resource loongson_pci_mem_resource = { >> .name = "pci memory space", >> @@ -82,7 +83,10 @@ static int __init pcibios_init(void) >> setup_pcimap(); >> >> loongson_pci_controller.io_map_base = mips_io_port_base; >> - >> +#ifdef CONFIG_LEFI_FIRMWARE_INTERFACE >> + loongson_pci_mem_resource.start = loongson_sysconf.pci_mem_start_addr; >> + loongson_pci_mem_resource.end = loongson_sysconf.pci_mem_end_addr; >> +#endif >> register_pci_controller(&loongson_pci_controller); >> >> return 0; >> diff --git a/arch/mips/loongson/common/reset.c >> b/arch/mips/loongson/common/reset.c >> index 65bfbb5..a60715e 100644 >> --- a/arch/mips/loongson/common/reset.c >> +++ b/arch/mips/loongson/common/reset.c >> @@ -16,6 +16,7 @@ >> #include <asm/reboot.h> >> >> #include <loongson.h> >> +#include <boot_param.h> >> >> static inline void loongson_reboot(void) >> { >> @@ -37,17 +38,37 @@ static inline void loongson_reboot(void) >> >> static void loongson_restart(char *command) >> { >> +#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE >> /* do preparation for reboot */ >> mach_prepare_reboot(); >> >> /* reboot via jumping to boot base address */ >> loongson_reboot(); >> +#else >> + void (*fw_restart)(void) = (void *)loongson_sysconf.restart_addr; >> + >> + fw_restart(); >> + while (1) { >> + if (cpu_wait) >> + cpu_wait(); >> + } >> +#endif >> } >> >> static void loongson_poweroff(void) >> { >> +#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE >> mach_prepare_shutdown(); >> unreachable(); >> +#else >> + void (*fw_poweroff)(void) = (void *)loongson_sysconf.poweroff_addr; >> + >> + fw_poweroff(); >> + while (1) { >> + if (cpu_wait) >> + cpu_wait(); >> + } >> +#endif >> } >> >> static void loongson_halt(void) >> -- >> 1.7.7.3 >> >> > > -- > Aurelien Jarno GPG: 1024D/F1BCDB73 > aurelien@xxxxxxxxxxx http://www.aurel32.net >