diff options
author | Helge Deller <deller@gmx.de> | 2018-03-25 18:52:58 +0200 |
---|---|---|
committer | Helge Deller <deller@gmx.de> | 2018-03-27 18:52:22 +0200 |
commit | a77ab0e7ce232a62adac3d85b9ae66d0f48385ac (patch) | |
tree | 5be2930f3a2697d91dbcab381e61367d61f9d289 /arch/parisc | |
parent | b845f66f78bf42a4ce98e5cfe0e94fab41dd0742 (diff) |
parisc: Add code generator for Qemu/SeaBIOS machine info
Qemu now supports emulating PA-RISC machines. For that a forked version
of SeaBIOS available at https://github.com/hdeller/seabios-hppa is used
which requires some information about the emulated machine.
This patch adds code to generate a header file with the necessary
information for SeaBIOS. The information is extracted from the firmware
the current kernel is running on.
Tested on a B160L workstation.
Signed-off-by: Helge Deller <deller@gmx.de>
Diffstat (limited to 'arch/parisc')
-rw-r--r-- | arch/parisc/kernel/drivers.c | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c index d4256145b74c..6afb595e0d86 100644 --- a/arch/parisc/kernel/drivers.c +++ b/arch/parisc/kernel/drivers.c @@ -895,6 +895,171 @@ void __init init_parisc_bus(void) get_device(&root); } +static __init void qemu_header(void) +{ + int num; + unsigned long *p; + + pr_info("--- cut here ---\n"); + pr_info("/* AUTO-GENERATED HEADER FILE FOR SEABIOS FIRMWARE */\n"); + pr_cont("/* generated with Linux kernel */\n"); + pr_cont("/* search for PARISC_QEMU_MACHINE_HEADER in Linux */\n\n"); + + pr_info("#define PARISC_MODEL \"%s\"\n\n", + boot_cpu_data.pdc.sys_model_name); + + pr_info("#define PARISC_PDC_MODEL 0x%lx, 0x%lx, 0x%lx, " + "0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx\n\n", + #define p ((unsigned long *)&boot_cpu_data.pdc.model) + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8]); + #undef p + + pr_info("#define PARISC_PDC_VERSION 0x%04lx\n\n", + boot_cpu_data.pdc.versions); + + pr_info("#define PARISC_PDC_CPUID 0x%04lx\n\n", + boot_cpu_data.pdc.cpuid); + + pr_info("#define PARISC_PDC_CAPABILITIES 0x%04lx\n\n", + boot_cpu_data.pdc.capabilities); + + pr_info("#define PARISC_PDC_ENTRY_ORG 0x%04lx\n\n", +#ifdef CONFIG_64BIT + (unsigned long)(PAGE0->mem_pdc_hi) << 32 | +#endif + (unsigned long)PAGE0->mem_pdc); + + pr_info("#define PARISC_PDC_CACHE_INFO"); + p = (unsigned long *) &cache_info; + for (num = 0; num < sizeof(cache_info); num += sizeof(unsigned long)) { + if (((num % 5) == 0)) { + pr_cont(" \\\n"); + pr_info("\t"); + } + pr_cont("%s0x%04lx", + num?", ":"", *p++); + } + pr_cont("\n\n"); +} + +static __init int qemu_print_hpa(struct device *lin_dev, void *data) +{ + struct parisc_device *dev = to_parisc_device(lin_dev); + unsigned long hpa = dev->hpa.start; + + pr_cont("\t{\t.hpa = 0x%08lx,\\\n", hpa); + pr_cont("\t\t.iodc = &iodc_data_hpa_%08lx,\\\n", hpa); + pr_cont("\t\t.mod_info = &mod_info_hpa_%08lx,\\\n", hpa); + pr_cont("\t\t.mod_path = &mod_path_hpa_%08lx,\\\n", hpa); + pr_cont("\t\t.num_addr = HPA_%08lx_num_addr,\\\n", hpa); + pr_cont("\t\t.add_addr = { HPA_%08lx_add_addr } },\\\n", hpa); + return 0; +} + + +static __init void qemu_footer(void) +{ + pr_info("\n\n#define PARISC_DEVICE_LIST \\\n"); + for_each_padev(qemu_print_hpa, NULL); + pr_cont("\t{ 0, }\n"); + pr_info("--- cut here ---\n"); +} + +/* print iodc data of the various hpa modules for qemu inclusion */ +static __init int qemu_print_iodc_data(struct device *lin_dev, void *data) +{ + struct parisc_device *dev = to_parisc_device(lin_dev); + unsigned long count; + unsigned long hpa = dev->hpa.start; + int status; + struct pdc_iodc iodc_data; + + int mod_index; + struct pdc_system_map_mod_info pdc_mod_info; + struct pdc_module_path mod_path; + + status = pdc_iodc_read(&count, hpa, 0, + &iodc_data, sizeof(iodc_data)); + if (status != PDC_OK) { + pr_info("No IODC data for hpa 0x%08lx\n", hpa); + return 0; + } + + pr_info("\n"); + + pr_info("#define HPA_%08lx_DESCRIPTION \"%s\"\n", + hpa, parisc_hardware_description(&dev->id)); + + mod_index = 0; + do { + status = pdc_system_map_find_mods(&pdc_mod_info, + &mod_path, mod_index++); + } while (status == PDC_OK && pdc_mod_info.mod_addr != hpa); + + pr_info("static struct pdc_system_map_mod_info" + " mod_info_hpa_%08lx = {\n", hpa); + #define DO(member) \ + pr_cont("\t." #member " = 0x%x,\n", \ + (unsigned int)pdc_mod_info.member) + DO(mod_addr); + DO(mod_pgs); + DO(add_addrs); + pr_cont("};\n"); + #undef DO + pr_info("static struct pdc_module_path " + "mod_path_hpa_%08lx = {\n", hpa); + pr_cont("\t.path = { "); + pr_cont(".flags = 0x%x, ", mod_path.path.flags); + pr_cont(".bc = { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x }, ", + (unsigned char)mod_path.path.bc[0], + (unsigned char)mod_path.path.bc[1], + (unsigned char)mod_path.path.bc[2], + (unsigned char)mod_path.path.bc[3], + (unsigned char)mod_path.path.bc[4], + (unsigned char)mod_path.path.bc[5]); + pr_cont(".mod = 0x%x ", mod_path.path.mod); + pr_cont(" },\n"); + pr_cont("\t.layers = { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x }\n", + mod_path.layers[0], mod_path.layers[1], mod_path.layers[2], + mod_path.layers[3], mod_path.layers[4], mod_path.layers[5]); + pr_cont("};\n"); + + pr_info("static struct pdc_iodc iodc_data_hpa_%08lx = {\n", hpa); + #define DO(member) \ + pr_cont("\t." #member " = 0x%04lx,\n", \ + (unsigned long)iodc_data.member) + DO(hversion_model); + DO(hversion); + DO(spa); + DO(type); + DO(sversion_rev); + DO(sversion_model); + DO(sversion_opt); + DO(rev); + DO(dep); + DO(features); + DO(checksum); + DO(length); + #undef DO + pr_cont("\t/* pad: 0x%04x, 0x%04x */\n", + iodc_data.pad[0], iodc_data.pad[1]); + pr_cont("};\n"); + + pr_info("#define HPA_%08lx_num_addr %d\n", hpa, dev->num_addrs); + pr_info("#define HPA_%08lx_add_addr ", hpa); + count = 0; + if (dev->num_addrs == 0) + pr_cont("0"); + while (count < dev->num_addrs) { + pr_cont("0x%08lx, ", dev->addr[count]); + count++; + } + pr_cont("\n\n"); + + return 0; +} + + static int print_one_device(struct device * dev, void * data) { @@ -911,4 +1076,10 @@ static int print_one_device(struct device * dev, void * data) void __init print_parisc_devices(void) { for_each_padev(print_one_device, NULL); + #define PARISC_QEMU_MACHINE_HEADER 0 + if (PARISC_QEMU_MACHINE_HEADER) { + qemu_header(); + for_each_padev(qemu_print_iodc_data, NULL); + qemu_footer(); + } } |