Re: [PATCH V16 04/12] MIPS: Loongson: Add UEFI-like firmware interface (LEFI) support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Jan 09, 2014 at 06:00:44PM +0800, Huacai Chen wrote:
> On Thu, Jan 9, 2014 at 6:58 AM, Aurelien Jarno <aurelien@xxxxxxxxxxx> wrote:
> 
> > On Wed, Jan 08, 2014 at 10:44:20AM +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>
> > > ---
> > >  arch/mips/include/asm/mach-loongson/boot_param.h |  159
> > ++++++++++++++++++++++
> > >  arch/mips/include/asm/mach-loongson/loongson.h   |    4 +-
> > >  arch/mips/loongson/common/env.c                  |   64 +++++++--
> > >  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, 285 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..234c0eb
> > > --- /dev/null
> > > +++ b/arch/mips/include/asm/mach-loongson/boot_param.h
> > > @@ -0,0 +1,159 @@
> > > +#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;
> > > +} __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;
> > > +};
> > > +
> > > +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 vgabios_addr;
> > > +};
> > > +
> > > +extern struct efi_memory_map_loongson *emap;
> > > +extern struct loongson_system_configuration loongson_sysconf;
> >
> > Thanks a lot for the loongson_sysconf struct, it looks a lot more clean
> > now. What about emap? Isn't there any risk that the kernel reuse the
> > corresponding memory and that its content is lost? It should be possible
> > to hold a copy of this struct in loongson_sysconf.
> >
> > emap is only used at system init, won't be used at runtime.

Then you can probably move the emap pointer in the loongson_sysconf
struct.

> >
> > > +#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..ba2b6df 100644
> > > --- a/arch/mips/loongson/common/env.c
> > > +++ b/arch/mips/loongson/common/env.c
> > > @@ -18,29 +18,37 @@
> > >   * option) any later version.
> > >   */
> > >  #include <linux/module.h>
> > > -
> > >  #include <asm/bootinfo.h>
> > > -
> > >  #include <loongson.h>
> > > +#include <boot_param.h>
> > > +
> > > +struct boot_params *boot_p;
> > > +struct loongson_params *loongson_p;
> > > +
> > > +struct efi_cpuinfo_loongson *ecpu;
> > > +struct efi_memory_map_loongson *emap;
> > > +struct system_loongson *esys;
> > > +struct irq_source_routing_table *eirq_source;
> > > +struct loongson_system_configuration loongson_sysconf;
> > >
> > > -unsigned long cpu_clock_freq;
> > > +u32 cpu_clock_freq;
> > >  EXPORT_SYMBOL(cpu_clock_freq);
> > > -unsigned long memsize, highmemsize;
> > >
> > >  #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 +56,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 +64,38 @@ void __init prom_init_env(void)
> > >       }
> > >       if (memsize == 0)
> > >               memsize = 256;
> > > -     if (bus_clock == 0)
> > > -             bus_clock = 66000000;
> > > +     pr_info("memsize=%ld, highmemsize=%ld\n", memsize, highmemsize);
> > > +#else
> > > +     /* 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);
> > > +     emap = (struct efi_memory_map_loongson *)
> > > +             ((u64)loongson_p + loongson_p->memory_offset);
> > > +     eirq_source = (struct irq_source_routing_table *)
> > > +             ((u64)loongson_p + loongson_p->irq_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.restart_addr = boot_p->reset_system.ResetWarm;
> > > +     loongson_sysconf.poweroff_addr = boot_p->reset_system.Shutdown;
> > > +
> > > +     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 +105,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..42b2431 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 < emap->nr_map; i++) {
> > > +             node_id = emap->map[i].node_id;
> > > +             mem_type = emap->map[i].mem_type;
> > > +
> > > +             if (node_id == 0) {
> > > +                     switch (mem_type) {
> > > +                     case SYSTEM_RAM_LOW:
> > > +                             add_memory_region(emap->map[i].mem_start,
> > > +                                     (u64)emap->map[i].mem_size << 20,
> > > +                                     BOOT_MEM_RAM);
> > > +                             break;
> > > +                     case SYSTEM_RAM_HIGH:
> > > +                             add_memory_region(emap->map[i].mem_start,
> > > +                                     (u64)emap->map[i].mem_size << 20,
> > > +                                     BOOT_MEM_RAM);
> > > +                             break;
> > > +                     case MEM_RESERVED:
> > > +                             add_memory_region(emap->map[i].mem_start,
> > > +                                     (u64)emap->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
> >
> >

-- 
Aurelien Jarno	                        GPG: 1024D/F1BCDB73
aurelien@xxxxxxxxxxx                 http://www.aurel32.net


[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux