diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/core.c | 5 | ||||
-rw-r--r-- | drivers/base/dd.c | 3 | ||||
-rw-r--r-- | drivers/base/memory.c | 62 | ||||
-rw-r--r-- | drivers/base/platform.c | 54 |
4 files changed, 83 insertions, 41 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index bc8729d603a..82c865452c7 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1764,8 +1764,8 @@ void device_shutdown(void) #ifdef CONFIG_PRINTK -static int __dev_printk(const char *level, const struct device *dev, - struct va_format *vaf) +int __dev_printk(const char *level, const struct device *dev, + struct va_format *vaf) { if (!dev) return printk("%s(NULL device *): %pV", level, vaf); @@ -1773,6 +1773,7 @@ static int __dev_printk(const char *level, const struct device *dev, return printk("%s%s %s: %pV", level, dev_driver_string(dev), dev_name(dev), vaf); } +EXPORT_SYMBOL(__dev_printk); int dev_printk(const char *level, const struct device *dev, const char *fmt, ...) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 6658da743c3..142e3d600f1 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -147,6 +147,9 @@ probe_failed: printk(KERN_WARNING "%s: probe of %s failed with error %d\n", drv->name, dev_name(dev), ret); + } else { + pr_debug("%s: probe of %s rejects match %d\n", + drv->name, dev_name(dev), ret); } /* * Ignore errors returned by ->probe so that the next driver can try diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 2840ed4668c..8272d92d22c 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -224,13 +224,48 @@ int memory_isolate_notify(unsigned long val, void *v) } /* + * The probe routines leave the pages reserved, just as the bootmem code does. + * Make sure they're still that way. + */ +static bool pages_correctly_reserved(unsigned long start_pfn, + unsigned long nr_pages) +{ + int i, j; + struct page *page; + unsigned long pfn = start_pfn; + + /* + * memmap between sections is not contiguous except with + * SPARSEMEM_VMEMMAP. We lookup the page once per section + * and assume memmap is contiguous within each section + */ + for (i = 0; i < sections_per_block; i++, pfn += PAGES_PER_SECTION) { + if (WARN_ON_ONCE(!pfn_valid(pfn))) + return false; + page = pfn_to_page(pfn); + + for (j = 0; j < PAGES_PER_SECTION; j++) { + if (PageReserved(page + j)) + continue; + + printk(KERN_WARNING "section number %ld page number %d " + "not reserved, was it already online?\n", + pfn_to_section_nr(pfn), j); + + return false; + } + } + + return true; +} + +/* * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is * OK to have direct references to sparsemem variables in here. */ static int memory_block_action(unsigned long phys_index, unsigned long action) { - int i; unsigned long start_pfn, start_paddr; unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block; struct page *first_page; @@ -238,26 +273,13 @@ memory_block_action(unsigned long phys_index, unsigned long action) first_page = pfn_to_page(phys_index << PFN_SECTION_SHIFT); - /* - * The probe routines leave the pages reserved, just - * as the bootmem code does. Make sure they're still - * that way. - */ - if (action == MEM_ONLINE) { - for (i = 0; i < nr_pages; i++) { - if (PageReserved(first_page+i)) - continue; - - printk(KERN_WARNING "section number %ld page number %d " - "not reserved, was it already online?\n", - phys_index, i); - return -EBUSY; - } - } - switch (action) { case MEM_ONLINE: start_pfn = page_to_pfn(first_page); + + if (!pages_correctly_reserved(start_pfn, nr_pages)) + return -EBUSY; + ret = online_pages(start_pfn, nr_pages); break; case MEM_OFFLINE: @@ -380,9 +402,13 @@ memory_probe_store(struct class *class, struct class_attribute *attr, u64 phys_addr; int nid; int i, ret; + unsigned long pages_per_block = PAGES_PER_SECTION * sections_per_block; phys_addr = simple_strtoull(buf, NULL, 0); + if (phys_addr & ((pages_per_block << PAGE_SHIFT) - 1)) + return -EINVAL; + for (i = 0; i < sections_per_block; i++) { nid = memory_add_physaddr_to_nid(phys_addr); ret = add_memory(nid, phys_addr, diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 99a5272d7c2..7a24895543e 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -375,52 +375,64 @@ void platform_device_unregister(struct platform_device *pdev) EXPORT_SYMBOL_GPL(platform_device_unregister); /** - * platform_device_register_resndata - add a platform-level device with + * platform_device_register_full - add a platform-level device with * resources and platform-specific data * - * @parent: parent device for the device we're adding - * @name: base name of the device we're adding - * @id: instance id - * @res: set of resources that needs to be allocated for the device - * @num: number of resources - * @data: platform specific data for this platform device - * @size: size of platform specific data + * @pdevinfo: data used to create device * * Returns &struct platform_device pointer on success, or ERR_PTR() on error. */ -struct platform_device *platform_device_register_resndata( - struct device *parent, - const char *name, int id, - const struct resource *res, unsigned int num, - const void *data, size_t size) +struct platform_device *platform_device_register_full( + struct platform_device_info *pdevinfo) { int ret = -ENOMEM; struct platform_device *pdev; - pdev = platform_device_alloc(name, id); + pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id); if (!pdev) - goto err; - - pdev->dev.parent = parent; + goto err_alloc; + + pdev->dev.parent = pdevinfo->parent; + + if (pdevinfo->dma_mask) { + /* + * This memory isn't freed when the device is put, + * I don't have a nice idea for that though. Conceptually + * dma_mask in struct device should not be a pointer. + * See http://thread.gmane.org/gmane.linux.kernel.pci/9081 + */ + pdev->dev.dma_mask = + kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL); + if (!pdev->dev.dma_mask) + goto err; + + *pdev->dev.dma_mask = pdevinfo->dma_mask; + pdev->dev.coherent_dma_mask = pdevinfo->dma_mask; + } - ret = platform_device_add_resources(pdev, res, num); + ret = platform_device_add_resources(pdev, + pdevinfo->res, pdevinfo->num_res); if (ret) goto err; - ret = platform_device_add_data(pdev, data, size); + ret = platform_device_add_data(pdev, + pdevinfo->data, pdevinfo->size_data); if (ret) goto err; ret = platform_device_add(pdev); if (ret) { err: + kfree(pdev->dev.dma_mask); + +err_alloc: platform_device_put(pdev); return ERR_PTR(ret); } return pdev; } -EXPORT_SYMBOL_GPL(platform_device_register_resndata); +EXPORT_SYMBOL_GPL(platform_device_register_full); static int platform_drv_probe(struct device *_dev) { @@ -614,7 +626,7 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) return rc; add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX, - (pdev->id_entry) ? pdev->id_entry->name : pdev->name); + pdev->name); return 0; } |