diff options
Diffstat (limited to 'arch/powerpc/kernel/ibmebus.c')
| -rw-r--r-- | arch/powerpc/kernel/ibmebus.c | 769 |
1 files changed, 516 insertions, 253 deletions
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index 9a8c9af43b2..1114d13ac19 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c @@ -37,23 +37,35 @@ */ #include <linux/init.h> +#include <linux/export.h> #include <linux/console.h> #include <linux/kobject.h> #include <linux/dma-mapping.h> #include <linux/interrupt.h> +#include <linux/of.h> +#include <linux/slab.h> +#include <linux/stat.h> +#include <linux/of_platform.h> #include <asm/ibmebus.h> -#include <asm/abs_addr.h> static struct device ibmebus_bus_device = { /* fake "parent" device */ - .bus_id = "ibmebus", + .init_name = "ibmebus", }; struct bus_type ibmebus_bus_type; +/* These devices will automatically be added to the bus during init */ +static struct of_device_id __initdata ibmebus_matches[] = { + { .compatible = "IBM,lhca" }, + { .compatible = "IBM,lhea" }, + {}, +}; + static void *ibmebus_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, - gfp_t flag) + gfp_t flag, + struct dma_attrs *attrs) { void *mem; @@ -65,37 +77,42 @@ static void *ibmebus_alloc_coherent(struct device *dev, static void ibmebus_free_coherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) + dma_addr_t dma_handle, + struct dma_attrs *attrs) { kfree(vaddr); } -static dma_addr_t ibmebus_map_single(struct device *dev, - void *ptr, - size_t size, - enum dma_data_direction direction) +static dma_addr_t ibmebus_map_page(struct device *dev, + struct page *page, + unsigned long offset, + size_t size, + enum dma_data_direction direction, + struct dma_attrs *attrs) { - return (dma_addr_t)(ptr); + return (dma_addr_t)(page_address(page) + offset); } -static void ibmebus_unmap_single(struct device *dev, - dma_addr_t dma_addr, - size_t size, - enum dma_data_direction direction) +static void ibmebus_unmap_page(struct device *dev, + dma_addr_t dma_addr, + size_t size, + enum dma_data_direction direction, + struct dma_attrs *attrs) { return; } static int ibmebus_map_sg(struct device *dev, - struct scatterlist *sg, - int nents, enum dma_data_direction direction) + struct scatterlist *sgl, + int nents, enum dma_data_direction direction, + struct dma_attrs *attrs) { + struct scatterlist *sg; int i; - for (i = 0; i < nents; i++) { - sg[i].dma_address = (dma_addr_t)page_address(sg[i].page) - + sg[i].offset; - sg[i].dma_length = sg[i].length; + for_each_sg(sgl, sg, nents, i) { + sg->dma_address = (dma_addr_t) sg_virt(sg); + sg->dma_length = sg->length; } return nents; @@ -103,369 +120,608 @@ static int ibmebus_map_sg(struct device *dev, static void ibmebus_unmap_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) + int nents, enum dma_data_direction direction, + struct dma_attrs *attrs) { return; } static int ibmebus_dma_supported(struct device *dev, u64 mask) { - return 1; + return mask == DMA_BIT_MASK(64); +} + +static u64 ibmebus_dma_get_required_mask(struct device *dev) +{ + return DMA_BIT_MASK(64); } -static struct dma_mapping_ops ibmebus_dma_ops = { - .alloc_coherent = ibmebus_alloc_coherent, - .free_coherent = ibmebus_free_coherent, - .map_single = ibmebus_map_single, - .unmap_single = ibmebus_unmap_single, - .map_sg = ibmebus_map_sg, - .unmap_sg = ibmebus_unmap_sg, - .dma_supported = ibmebus_dma_supported, +static struct dma_map_ops ibmebus_dma_ops = { + .alloc = ibmebus_alloc_coherent, + .free = ibmebus_free_coherent, + .map_sg = ibmebus_map_sg, + .unmap_sg = ibmebus_unmap_sg, + .dma_supported = ibmebus_dma_supported, + .get_required_mask = ibmebus_dma_get_required_mask, + .map_page = ibmebus_map_page, + .unmap_page = ibmebus_unmap_page, }; -static int ibmebus_bus_probe(struct device *dev) +static int ibmebus_match_path(struct device *dev, void *data) { - struct ibmebus_dev *ibmebusdev = to_ibmebus_dev(dev); - struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver); - const struct of_device_id *id; - int error = -ENODEV; + struct device_node *dn = to_platform_device(dev)->dev.of_node; + return (dn->full_name && + (strcasecmp((char *)data, dn->full_name) == 0)); +} - if (!ibmebusdrv->probe) - return error; +static int ibmebus_match_node(struct device *dev, void *data) +{ + return to_platform_device(dev)->dev.of_node == data; +} - id = of_match_device(ibmebusdrv->id_table, &ibmebusdev->ofdev); - if (id) { - error = ibmebusdrv->probe(ibmebusdev, id); - } +static int ibmebus_create_device(struct device_node *dn) +{ + struct platform_device *dev; + int ret; - return error; + dev = of_device_alloc(dn, NULL, &ibmebus_bus_device); + if (!dev) + return -ENOMEM; + + dev->dev.bus = &ibmebus_bus_type; + dev->dev.archdata.dma_ops = &ibmebus_dma_ops; + + ret = of_device_add(dev); + if (ret) + platform_device_put(dev); + return ret; } -static int ibmebus_bus_remove(struct device *dev) +static int ibmebus_create_devices(const struct of_device_id *matches) { - struct ibmebus_dev *ibmebusdev = to_ibmebus_dev(dev); - struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver); + struct device_node *root, *child; + int ret = 0; - if (ibmebusdrv->remove) { - return ibmebusdrv->remove(ibmebusdev); + root = of_find_node_by_path("/"); + + for_each_child_of_node(root, child) { + if (!of_match_node(matches, child)) + continue; + + if (bus_find_device(&ibmebus_bus_type, NULL, child, + ibmebus_match_node)) + continue; + + ret = ibmebus_create_device(child); + if (ret) { + printk(KERN_ERR "%s: failed to create device (%i)", + __func__, ret); + of_node_put(child); + break; + } } - return 0; + of_node_put(root); + return ret; } -static void __devinit ibmebus_dev_release(struct device *dev) +int ibmebus_register_driver(struct platform_driver *drv) { - of_node_put(to_ibmebus_dev(dev)->ofdev.node); - kfree(to_ibmebus_dev(dev)); + /* If the driver uses devices that ibmebus doesn't know, add them */ + ibmebus_create_devices(drv->driver.of_match_table); + + drv->driver.bus = &ibmebus_bus_type; + return driver_register(&drv->driver); } +EXPORT_SYMBOL(ibmebus_register_driver); -static int __devinit ibmebus_register_device_common( - struct ibmebus_dev *dev, const char *name) +void ibmebus_unregister_driver(struct platform_driver *drv) { - int err = 0; + driver_unregister(&drv->driver); +} +EXPORT_SYMBOL(ibmebus_unregister_driver); - dev->ofdev.dev.parent = &ibmebus_bus_device; - dev->ofdev.dev.bus = &ibmebus_bus_type; - dev->ofdev.dev.release = ibmebus_dev_release; +int ibmebus_request_irq(u32 ist, irq_handler_t handler, + unsigned long irq_flags, const char *devname, + void *dev_id) +{ + unsigned int irq = irq_create_mapping(NULL, ist); - dev->ofdev.dev.archdata.of_node = dev->ofdev.node; - dev->ofdev.dev.archdata.dma_ops = &ibmebus_dma_ops; - dev->ofdev.dev.archdata.numa_node = of_node_to_nid(dev->ofdev.node); + if (irq == NO_IRQ) + return -EINVAL; - /* An ibmebusdev is based on a of_device. We have to change the - * bus type to use our own DMA mapping operations. - */ - if ((err = of_device_register(&dev->ofdev)) != 0) { - printk(KERN_ERR "%s: failed to register device (%d).\n", - __FUNCTION__, err); - return -ENODEV; - } + return request_irq(irq, handler, irq_flags, devname, dev_id); +} +EXPORT_SYMBOL(ibmebus_request_irq); - return 0; +void ibmebus_free_irq(u32 ist, void *dev_id) +{ + unsigned int irq = irq_find_mapping(NULL, ist); + + free_irq(irq, dev_id); + irq_dispose_mapping(irq); +} +EXPORT_SYMBOL(ibmebus_free_irq); + +static char *ibmebus_chomp(const char *in, size_t count) +{ + char *out = kmalloc(count + 1, GFP_KERNEL); + + if (!out) + return NULL; + + memcpy(out, in, count); + out[count] = '\0'; + if (out[count - 1] == '\n') + out[count - 1] = '\0'; + + return out; } -static struct ibmebus_dev* __devinit ibmebus_register_device_node( - struct device_node *dn) +static ssize_t ibmebus_store_probe(struct bus_type *bus, + const char *buf, size_t count) { - struct ibmebus_dev *dev; - const char *loc_code; - int length; + struct device_node *dn = NULL; + char *path; + ssize_t rc = 0; - loc_code = of_get_property(dn, "ibm,loc-code", NULL); - if (!loc_code) { - printk(KERN_WARNING "%s: node %s missing 'ibm,loc-code'\n", - __FUNCTION__, dn->name ? dn->name : "<unknown>"); - return ERR_PTR(-EINVAL); - } + path = ibmebus_chomp(buf, count); + if (!path) + return -ENOMEM; - if (strlen(loc_code) == 0) { - printk(KERN_WARNING "%s: 'ibm,loc-code' is invalid\n", - __FUNCTION__); - return ERR_PTR(-EINVAL); + if (bus_find_device(&ibmebus_bus_type, NULL, path, + ibmebus_match_path)) { + printk(KERN_WARNING "%s: %s has already been probed\n", + __func__, path); + rc = -EEXIST; + goto out; } - dev = kzalloc(sizeof(struct ibmebus_dev), GFP_KERNEL); - if (!dev) { - return ERR_PTR(-ENOMEM); + if ((dn = of_find_node_by_path(path))) { + rc = ibmebus_create_device(dn); + of_node_put(dn); + } else { + printk(KERN_WARNING "%s: no such device node: %s\n", + __func__, path); + rc = -ENODEV; } - dev->ofdev.node = of_node_get(dn); +out: + kfree(path); + if (rc) + return rc; + return count; +} +static BUS_ATTR(probe, S_IWUSR, NULL, ibmebus_store_probe); + +static ssize_t ibmebus_store_remove(struct bus_type *bus, + const char *buf, size_t count) +{ + struct device *dev; + char *path; + + path = ibmebus_chomp(buf, count); + if (!path) + return -ENOMEM; + + if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path, + ibmebus_match_path))) { + of_device_unregister(to_platform_device(dev)); - length = strlen(loc_code); - memcpy(dev->ofdev.dev.bus_id, loc_code - + (length - min(length, BUS_ID_SIZE - 1)), - min(length, BUS_ID_SIZE - 1)); + kfree(path); + return count; + } else { + printk(KERN_WARNING "%s: %s not on the bus\n", + __func__, path); - /* Register with generic device framework. */ - if (ibmebus_register_device_common(dev, dn->name) != 0) { - kfree(dev); - return ERR_PTR(-ENODEV); + kfree(path); + return -ENODEV; } +} +static BUS_ATTR(remove, S_IWUSR, NULL, ibmebus_store_remove); + +static struct attribute *ibmbus_bus_attrs[] = { + &bus_attr_probe.attr, + &bus_attr_remove.attr, + NULL, +}; +ATTRIBUTE_GROUPS(ibmbus_bus); + +static int ibmebus_bus_bus_match(struct device *dev, struct device_driver *drv) +{ + const struct of_device_id *matches = drv->of_match_table; + + if (!matches) + return 0; - return dev; + return of_match_device(matches, dev) != NULL; } -static void ibmebus_probe_of_nodes(char* name) +static int ibmebus_bus_device_probe(struct device *dev) { - struct device_node *dn = NULL; + int error = -ENODEV; + struct platform_driver *drv; + struct platform_device *of_dev; - while ((dn = of_find_node_by_name(dn, name))) { - if (IS_ERR(ibmebus_register_device_node(dn))) { - of_node_put(dn); - return; - } - } + drv = to_platform_driver(dev->driver); + of_dev = to_platform_device(dev); + + if (!drv->probe) + return error; - of_node_put(dn); + of_dev_get(of_dev); - return; + if (of_driver_match_device(dev, dev->driver)) + error = drv->probe(of_dev); + if (error) + of_dev_put(of_dev); + + return error; } -static void ibmebus_add_devices_by_id(struct of_device_id *idt) +static int ibmebus_bus_device_remove(struct device *dev) { - while (strlen(idt->name) > 0) { - ibmebus_probe_of_nodes(idt->name); - idt++; - } + struct platform_device *of_dev = to_platform_device(dev); + struct platform_driver *drv = to_platform_driver(dev->driver); - return; + if (dev->driver && drv->remove) + drv->remove(of_dev); + return 0; } -static int ibmebus_match_name(struct device *dev, void *data) +static void ibmebus_bus_device_shutdown(struct device *dev) { - const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev); - const char *name; + struct platform_device *of_dev = to_platform_device(dev); + struct platform_driver *drv = to_platform_driver(dev->driver); - name = of_get_property(ebus_dev->ofdev.node, "name", NULL); + if (dev->driver && drv->shutdown) + drv->shutdown(of_dev); +} - if (name && (strcmp(data, name) == 0)) - return 1; +/* + * ibmebus_bus_device_attrs + */ +static ssize_t devspec_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *ofdev; - return 0; + ofdev = to_platform_device(dev); + return sprintf(buf, "%s\n", ofdev->dev.of_node->full_name); } -static int ibmebus_unregister_device(struct device *dev) +static ssize_t name_show(struct device *dev, + struct device_attribute *attr, char *buf) { - of_device_unregister(to_of_device(dev)); + struct platform_device *ofdev; - return 0; + ofdev = to_platform_device(dev); + return sprintf(buf, "%s\n", ofdev->dev.of_node->name); } -static void ibmebus_remove_devices_by_id(struct of_device_id *idt) +static ssize_t modalias_show(struct device *dev, + struct device_attribute *attr, char *buf) { - struct device *dev; + ssize_t len = of_device_get_modalias(dev, buf, PAGE_SIZE - 2); + buf[len] = '\n'; + buf[len+1] = 0; + return len+1; +} - while (strlen(idt->name) > 0) { - while ((dev = bus_find_device(&ibmebus_bus_type, NULL, - (void*)idt->name, - ibmebus_match_name))) { - ibmebus_unregister_device(dev); - } - idt++; - } +struct device_attribute ibmebus_bus_device_attrs[] = { + __ATTR_RO(devspec), + __ATTR_RO(name), + __ATTR_RO(modalias), + __ATTR_NULL +}; - return; +#ifdef CONFIG_PM_SLEEP +static int ibmebus_bus_legacy_suspend(struct device *dev, pm_message_t mesg) +{ + struct platform_device *of_dev = to_platform_device(dev); + struct platform_driver *drv = to_platform_driver(dev->driver); + int ret = 0; + + if (dev->driver && drv->suspend) + ret = drv->suspend(of_dev, mesg); + return ret; } -int ibmebus_register_driver(struct ibmebus_driver *drv) +static int ibmebus_bus_legacy_resume(struct device *dev) { - int err = 0; + struct platform_device *of_dev = to_platform_device(dev); + struct platform_driver *drv = to_platform_driver(dev->driver); + int ret = 0; - drv->driver.name = drv->name; - drv->driver.bus = &ibmebus_bus_type; - drv->driver.probe = ibmebus_bus_probe; - drv->driver.remove = ibmebus_bus_remove; + if (dev->driver && drv->resume) + ret = drv->resume(of_dev); + return ret; +} - if ((err = driver_register(&drv->driver) != 0)) - return err; +static int ibmebus_bus_pm_prepare(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; - /* remove all supported devices first, in case someone - * probed them manually before registering the driver */ - ibmebus_remove_devices_by_id(drv->id_table); - ibmebus_add_devices_by_id(drv->id_table); + if (drv && drv->pm && drv->pm->prepare) + ret = drv->pm->prepare(dev); - return 0; + return ret; } -EXPORT_SYMBOL(ibmebus_register_driver); -void ibmebus_unregister_driver(struct ibmebus_driver *drv) +static void ibmebus_bus_pm_complete(struct device *dev) { - driver_unregister(&drv->driver); - ibmebus_remove_devices_by_id(drv->id_table); + struct device_driver *drv = dev->driver; + + if (drv && drv->pm && drv->pm->complete) + drv->pm->complete(dev); } -EXPORT_SYMBOL(ibmebus_unregister_driver); -int ibmebus_request_irq(struct ibmebus_dev *dev, - u32 ist, - irq_handler_t handler, - unsigned long irq_flags, const char * devname, - void *dev_id) +#ifdef CONFIG_SUSPEND + +static int ibmebus_bus_pm_suspend(struct device *dev) { - unsigned int irq = irq_create_mapping(NULL, ist); + struct device_driver *drv = dev->driver; + int ret = 0; - if (irq == NO_IRQ) - return -EINVAL; + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->suspend) + ret = drv->pm->suspend(dev); + } else { + ret = ibmebus_bus_legacy_suspend(dev, PMSG_SUSPEND); + } - return request_irq(irq, handler, - irq_flags, devname, dev_id); + return ret; } -EXPORT_SYMBOL(ibmebus_request_irq); -void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id) +static int ibmebus_bus_pm_suspend_noirq(struct device *dev) { - unsigned int irq = irq_find_mapping(NULL, ist); + struct device_driver *drv = dev->driver; + int ret = 0; - free_irq(irq, dev_id); + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->suspend_noirq) + ret = drv->pm->suspend_noirq(dev); + } + + return ret; } -EXPORT_SYMBOL(ibmebus_free_irq); -static int ibmebus_bus_match(struct device *dev, struct device_driver *drv) +static int ibmebus_bus_pm_resume(struct device *dev) { - const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev); - struct ibmebus_driver *ebus_drv = to_ibmebus_driver(drv); - const struct of_device_id *ids = ebus_drv->id_table; - const struct of_device_id *found_id; + struct device_driver *drv = dev->driver; + int ret = 0; - if (!ids) + if (!drv) return 0; - found_id = of_match_device(ids, &ebus_dev->ofdev); - if (found_id) - return 1; + if (drv->pm) { + if (drv->pm->resume) + ret = drv->pm->resume(dev); + } else { + ret = ibmebus_bus_legacy_resume(dev); + } - return 0; + return ret; } -static ssize_t name_show(struct device *dev, - struct device_attribute *attr, char *buf) +static int ibmebus_bus_pm_resume_noirq(struct device *dev) { - struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev); - const char *name = of_get_property(ebus_dev->ofdev.node, "name", NULL); - return sprintf(buf, "%s\n", name); + struct device_driver *drv = dev->driver; + int ret = 0; + + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->resume_noirq) + ret = drv->pm->resume_noirq(dev); + } + + return ret; } -static struct device_attribute ibmebus_dev_attrs[] = { - __ATTR_RO(name), - __ATTR_NULL -}; +#else /* !CONFIG_SUSPEND */ -static int ibmebus_match_path(struct device *dev, void *data) +#define ibmebus_bus_pm_suspend NULL +#define ibmebus_bus_pm_resume NULL +#define ibmebus_bus_pm_suspend_noirq NULL +#define ibmebus_bus_pm_resume_noirq NULL + +#endif /* !CONFIG_SUSPEND */ + +#ifdef CONFIG_HIBERNATE_CALLBACKS + +static int ibmebus_bus_pm_freeze(struct device *dev) { - int rc; - struct device_node *dn = - of_node_get(to_ibmebus_dev(dev)->ofdev.node); + struct device_driver *drv = dev->driver; + int ret = 0; + + if (!drv) + return 0; - rc = (dn->full_name && (strcasecmp((char*)data, dn->full_name) == 0)); + if (drv->pm) { + if (drv->pm->freeze) + ret = drv->pm->freeze(dev); + } else { + ret = ibmebus_bus_legacy_suspend(dev, PMSG_FREEZE); + } - of_node_put(dn); - return rc; + return ret; } -static char *ibmebus_chomp(const char *in, size_t count) +static int ibmebus_bus_pm_freeze_noirq(struct device *dev) { - char *out = (char*)kmalloc(count + 1, GFP_KERNEL); - if (!out) - return NULL; + struct device_driver *drv = dev->driver; + int ret = 0; - memcpy(out, in, count); - out[count] = '\0'; - if (out[count - 1] == '\n') - out[count - 1] = '\0'; + if (!drv) + return 0; - return out; + if (drv->pm) { + if (drv->pm->freeze_noirq) + ret = drv->pm->freeze_noirq(dev); + } + + return ret; } -static ssize_t ibmebus_store_probe(struct bus_type *bus, - const char *buf, size_t count) +static int ibmebus_bus_pm_thaw(struct device *dev) { - struct device_node *dn = NULL; - struct ibmebus_dev *dev; - char *path; - ssize_t rc; + struct device_driver *drv = dev->driver; + int ret = 0; - path = ibmebus_chomp(buf, count); - if (!path) - return -ENOMEM; + if (!drv) + return 0; - if (bus_find_device(&ibmebus_bus_type, NULL, path, - ibmebus_match_path)) { - printk(KERN_WARNING "%s: %s has already been probed\n", - __FUNCTION__, path); - rc = -EINVAL; - goto out; + if (drv->pm) { + if (drv->pm->thaw) + ret = drv->pm->thaw(dev); + } else { + ret = ibmebus_bus_legacy_resume(dev); } - if ((dn = of_find_node_by_path(path))) { - dev = ibmebus_register_device_node(dn); - of_node_put(dn); - rc = IS_ERR(dev) ? PTR_ERR(dev) : count; + return ret; +} + +static int ibmebus_bus_pm_thaw_noirq(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->thaw_noirq) + ret = drv->pm->thaw_noirq(dev); + } + + return ret; +} + +static int ibmebus_bus_pm_poweroff(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->poweroff) + ret = drv->pm->poweroff(dev); } else { - printk(KERN_WARNING "%s: no such device node: %s\n", - __FUNCTION__, path); - rc = -ENODEV; + ret = ibmebus_bus_legacy_suspend(dev, PMSG_HIBERNATE); } -out: - kfree(path); - return rc; + return ret; } -static ssize_t ibmebus_store_remove(struct bus_type *bus, - const char *buf, size_t count) +static int ibmebus_bus_pm_poweroff_noirq(struct device *dev) { - struct device *dev; - char *path; + struct device_driver *drv = dev->driver; + int ret = 0; - path = ibmebus_chomp(buf, count); - if (!path) - return -ENOMEM; + if (!drv) + return 0; - if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path, - ibmebus_match_path))) { - ibmebus_unregister_device(dev); + if (drv->pm) { + if (drv->pm->poweroff_noirq) + ret = drv->pm->poweroff_noirq(dev); + } - kfree(path); - return count; + return ret; +} + +static int ibmebus_bus_pm_restore(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->restore) + ret = drv->pm->restore(dev); } else { - printk(KERN_WARNING "%s: %s not on the bus\n", - __FUNCTION__, path); + ret = ibmebus_bus_legacy_resume(dev); + } - kfree(path); - return -ENODEV; + return ret; +} + +static int ibmebus_bus_pm_restore_noirq(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (!drv) + return 0; + + if (drv->pm) { + if (drv->pm->restore_noirq) + ret = drv->pm->restore_noirq(dev); } + + return ret; } -static struct bus_attribute ibmebus_bus_attrs[] = { - __ATTR(probe, S_IWUSR, NULL, ibmebus_store_probe), - __ATTR(remove, S_IWUSR, NULL, ibmebus_store_remove), - __ATTR_NULL +#else /* !CONFIG_HIBERNATE_CALLBACKS */ + +#define ibmebus_bus_pm_freeze NULL +#define ibmebus_bus_pm_thaw NULL +#define ibmebus_bus_pm_poweroff NULL +#define ibmebus_bus_pm_restore NULL +#define ibmebus_bus_pm_freeze_noirq NULL +#define ibmebus_bus_pm_thaw_noirq NULL +#define ibmebus_bus_pm_poweroff_noirq NULL +#define ibmebus_bus_pm_restore_noirq NULL + +#endif /* !CONFIG_HIBERNATE_CALLBACKS */ + +static struct dev_pm_ops ibmebus_bus_dev_pm_ops = { + .prepare = ibmebus_bus_pm_prepare, + .complete = ibmebus_bus_pm_complete, + .suspend = ibmebus_bus_pm_suspend, + .resume = ibmebus_bus_pm_resume, + .freeze = ibmebus_bus_pm_freeze, + .thaw = ibmebus_bus_pm_thaw, + .poweroff = ibmebus_bus_pm_poweroff, + .restore = ibmebus_bus_pm_restore, + .suspend_noirq = ibmebus_bus_pm_suspend_noirq, + .resume_noirq = ibmebus_bus_pm_resume_noirq, + .freeze_noirq = ibmebus_bus_pm_freeze_noirq, + .thaw_noirq = ibmebus_bus_pm_thaw_noirq, + .poweroff_noirq = ibmebus_bus_pm_poweroff_noirq, + .restore_noirq = ibmebus_bus_pm_restore_noirq, }; +#define IBMEBUS_BUS_PM_OPS_PTR (&ibmebus_bus_dev_pm_ops) + +#else /* !CONFIG_PM_SLEEP */ + +#define IBMEBUS_BUS_PM_OPS_PTR NULL + +#endif /* !CONFIG_PM_SLEEP */ + struct bus_type ibmebus_bus_type = { .name = "ibmebus", - .match = ibmebus_bus_match, - .dev_attrs = ibmebus_dev_attrs, - .bus_attrs = ibmebus_bus_attrs + .uevent = of_device_uevent_modalias, + .bus_groups = ibmbus_bus_groups, + .match = ibmebus_bus_bus_match, + .probe = ibmebus_bus_device_probe, + .remove = ibmebus_bus_device_remove, + .shutdown = ibmebus_bus_device_shutdown, + .dev_attrs = ibmebus_bus_device_attrs, + .pm = IBMEBUS_BUS_PM_OPS_PTR, }; EXPORT_SYMBOL(ibmebus_bus_type); @@ -477,20 +733,27 @@ static int __init ibmebus_bus_init(void) err = bus_register(&ibmebus_bus_type); if (err) { - printk(KERN_ERR ":%s: failed to register IBM eBus.\n", - __FUNCTION__); + printk(KERN_ERR "%s: failed to register IBM eBus.\n", + __func__); return err; } err = device_register(&ibmebus_bus_device); if (err) { printk(KERN_WARNING "%s: device_register returned %i\n", - __FUNCTION__, err); + __func__, err); bus_unregister(&ibmebus_bus_type); return err; } + err = ibmebus_create_devices(ibmebus_matches); + if (err) { + device_unregister(&ibmebus_bus_device); + bus_unregister(&ibmebus_bus_type); + return err; + } + return 0; } -__initcall(ibmebus_bus_init); +postcore_initcall(ibmebus_bus_init); |
