diff options
Diffstat (limited to 'arch/parisc/kernel/drivers.c')
-rw-r--r-- | arch/parisc/kernel/drivers.c | 227 |
1 files changed, 198 insertions, 29 deletions
diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c index 29b99b8964aa..5eb979d04b90 100644 --- a/arch/parisc/kernel/drivers.c +++ b/arch/parisc/kernel/drivers.c @@ -135,7 +135,7 @@ static int parisc_driver_probe(struct device *dev) return rc; } -static int parisc_driver_remove(struct device *dev) +static int __exit parisc_driver_remove(struct device *dev) { struct parisc_device *pa_dev = to_parisc_device(dev); struct parisc_driver *pa_drv = to_parisc_driver(dev->driver); @@ -154,17 +154,14 @@ int register_parisc_driver(struct parisc_driver *driver) { /* FIXME: we need this because apparently the sti * driver can be registered twice */ - if(driver->drv.name) { - printk(KERN_WARNING - "BUG: skipping previously registered driver %s\n", - driver->name); + if (driver->drv.name) { + pr_warn("BUG: skipping previously registered driver %s\n", + driver->name); return 1; } if (!driver->probe) { - printk(KERN_WARNING - "BUG: driver %s has no probe routine\n", - driver->name); + pr_warn("BUG: driver %s has no probe routine\n", driver->name); return 1; } @@ -205,7 +202,7 @@ static int match_and_count(struct device * dev, void * data) * Use by IOMMU support to "guess" the right size IOPdir. * Formula is something like memsize/(num_iommu * entry_size). */ -int count_parisc_driver(struct parisc_driver *driver) +int __init count_parisc_driver(struct parisc_driver *driver) { struct match_count m = { .driver = driver, @@ -397,7 +394,7 @@ static void setup_bus_id(struct parisc_device *padev) dev_set_name(&padev->dev, name); } -struct parisc_device * create_tree_node(char id, struct device *parent) +struct parisc_device * __init create_tree_node(char id, struct device *parent) { struct parisc_device *dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) @@ -448,7 +445,8 @@ static int match_by_id(struct device * dev, void * data) * Checks all the children of @parent for a matching @id. If none * found, it allocates a new device and returns it. */ -static struct parisc_device * alloc_tree_node(struct device *parent, char id) +static struct parisc_device * __init alloc_tree_node( + struct device *parent, char id) { struct match_id_data d = { .id = id, @@ -471,7 +469,7 @@ static struct parisc_device *create_parisc_device(struct hardware_path *modpath) return alloc_tree_node(parent, modpath->mod); } -struct parisc_device * +struct parisc_device * __init alloc_pa_dev(unsigned long hpa, struct hardware_path *mod_path) { int status; @@ -490,12 +488,9 @@ alloc_pa_dev(unsigned long hpa, struct hardware_path *mod_path) dev = create_parisc_device(mod_path); if (dev->id.hw_type != HPHW_FAULTY) { - printk(KERN_ERR "Two devices have hardware path [%s]. " - "IODC data for second device: " - "%02x%02x%02x%02x%02x%02x\n" - "Rearranging GSC cards sometimes helps\n", - parisc_pathname(dev), iodc_data[0], iodc_data[1], - iodc_data[3], iodc_data[4], iodc_data[5], iodc_data[6]); + pr_err("Two devices have hardware path [%s]. IODC data for second device: %7phN\n" + "Rearranging GSC cards sometimes helps\n", + parisc_pathname(dev), iodc_data); return NULL; } @@ -527,8 +522,7 @@ alloc_pa_dev(unsigned long hpa, struct hardware_path *mod_path) * the keyboard controller */ if ((hpa & 0xfff) == 0 && insert_resource(&iomem_resource, &dev->hpa)) - printk("Unable to claim HPA %lx for device %s\n", - hpa, name); + pr_warn("Unable to claim HPA %lx for device %s\n", hpa, name); return dev; } @@ -609,7 +603,7 @@ struct bus_type parisc_bus_type = { .uevent = parisc_uevent, .dev_groups = parisc_device_groups, .probe = parisc_driver_probe, - .remove = parisc_driver_remove, + .remove = __exit_p(parisc_driver_remove), }; /** @@ -619,7 +613,7 @@ struct bus_type parisc_bus_type = { * Search the driver list for a driver that is willing to manage * this device. */ -int register_parisc_device(struct parisc_device *dev) +int __init register_parisc_device(struct parisc_device *dev) { if (!dev) return 0; @@ -651,6 +645,10 @@ static int match_pci_device(struct device *dev, int index, (modpath->mod == PCI_FUNC(devfn))); } + /* index might be out of bounds for bc[] */ + if (index >= 6) + return 0; + id = PCI_SLOT(pdev->devfn) | (PCI_FUNC(pdev->devfn) << 5); return (modpath->bc[index] == id); } @@ -791,7 +789,7 @@ EXPORT_SYMBOL(device_to_hwpath); static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high, struct device *parent); -void walk_lower_bus(struct parisc_device *dev) +static void walk_lower_bus(struct parisc_device *dev) { unsigned long io_io_low, io_io_high; @@ -821,8 +819,8 @@ void walk_lower_bus(struct parisc_device *dev) * devices which are not physically connected (such as extra serial & * keyboard ports). This problem is not yet solved. */ -static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high, - struct device *parent) +static void __init walk_native_bus(unsigned long io_io_low, + unsigned long io_io_high, struct device *parent) { int i, devices_found = 0; unsigned long hpa = io_io_low; @@ -857,7 +855,7 @@ static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high, * PDC doesn't tell us about all devices in the system. This routine * finds devices connected to the central bus. */ -void walk_central_bus(void) +void __init walk_central_bus(void) { walk_native_bus(CENTRAL_BUS_ADDR, CENTRAL_BUS_ADDR + (MAX_NATIVE_DEVICES * NATIVE_DEVICE_OFFSET), @@ -870,7 +868,7 @@ static void print_parisc_device(struct parisc_device *dev) static int count; print_pa_hwpath(dev, hw_path); - printk(KERN_INFO "%d. %s at 0x%px [%s] { %d, 0x%x, 0x%.3x, 0x%.5x }", + pr_info("%d. %s at 0x%px [%s] { %d, 0x%x, 0x%.3x, 0x%.5x }", ++count, dev->name, (void*) dev->hpa.start, hw_path, dev->id.hw_type, dev->id.hversion_rev, dev->id.hversion, dev->id.sversion); @@ -886,7 +884,7 @@ static void print_parisc_device(struct parisc_device *dev) /** * init_parisc_bus - Some preparation to be done before inventory */ -void init_parisc_bus(void) +void __init init_parisc_bus(void) { if (bus_register(&parisc_bus_type)) panic("Could not register PA-RISC bus type\n"); @@ -895,6 +893,171 @@ void 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) { @@ -908,7 +1071,13 @@ static int print_one_device(struct device * dev, void * data) /** * print_parisc_devices - Print out a list of devices found in this system */ -void print_parisc_devices(void) +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(); + } } |