[PATCH] parisc: Add code generator for Qemu/SeaBIOS machine info

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

 



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@xxxxxx>

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();
+	}
 }
--
To unsubscribe from this list: send the line "unsubscribe linux-parisc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux SoC]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux