linux-mips
[Top] [All Lists]

Re: [PATCH V19 05/13] MIPS: Loongson: Add UEFI-like firmware interface (

To: "Aurelien Jarno" <aurelien@aurel32.net>
Subject: Re: [PATCH V19 05/13] MIPS: Loongson: Add UEFI-like firmware interface (LEFI) support
From: "陈华才" <chenhc@lemote.com>
Date: Mon, 17 Feb 2014 13:15:01 +0800
Cc: "Ralf Baechle" <ralf@linux-mips.org>, "John Crispin" <john@phrozen.org>, "Steven J. Hill" <steven.hill@imgtec.com>, linux-mips@linux-mips.org, "Fuxin Zhang" <zhangfx@lemote.com>, "Zhangjin Wu" <wuzhangjin@gmail.com>, "Hongliang Tao" <taohl@lemote.com>, "Hua Yan" <yanh@lemote.com>
Importance: Normal
In-reply-to: <20140216211259.GA428@hall.aurel32.net>
List-archive: <http://www.linux-mips.org/archives/linux-mips/>
List-help: <mailto:ecartis@linux-mips.org?Subject=help>
List-id: linux-mips <linux-mips.eddie.linux-mips.org>
List-owner: <mailto:ralf@linux-mips.org>
List-post: <mailto:linux-mips@linux-mips.org>
List-software: Ecartis version 1.0.0
List-subscribe: <mailto:ecartis@linux-mips.org?subject=subscribe%20linux-mips>
List-unsubscribe: <mailto:ecartis@linux-mips.org?subject=unsubscribe%20linux-mips>
Original-recipient: rfc822;linux-mips@linux-mips.org
References: <1392537690-5961-1-git-send-email-chenhc@lemote.com> <1392537690-5961-6-git-send-email-chenhc@lemote.com> <20140216211259.GA428@hall.aurel32.net>
Sender: linux-mips-bounce@linux-mips.org
User-agent: SquirrelMail/1.4.22
> 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@lemote.com>
>> Signed-off-by: Hongliang Tao <taohl@lemote.com>
>> Signed-off-by: Hua Yan <yanh@lemote.com>
>> Tested-by: Alex Smith <alex.smith@imgtec.com>
>> Reviewed-by: Alex Smith <alex.smith@imgtec.com>
>> ---
>>  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 = (&current_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@aurel32.net                 http://www.aurel32.net
>



<Prev in Thread] Current Thread [Next in Thread>