From cebf8fd16900fdfd58c0028617944f808f97fe50 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Sun, 10 Jul 2016 19:27:36 +0800 Subject: driver core: fix race between creating/querying glue dir and its cleanup The global mutex of 'gdp_mutex' is used to serialize creating/querying glue dir and its cleanup. Turns out it isn't a perfect way because part(kobj_kset_leave()) of the actual cleanup action() is done inside the release handler of the glue dir kobject. That means gdp_mutex has to be held before releasing the last reference count of the glue dir kobject. This patch moves glue dir's cleanup after kobject_del() in device_del() for avoiding the race. Cc: Yijing Wang Reported-by: Chandra Sekhar Lingutla Signed-off-by: Ming Lei Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/core.c b/drivers/base/core.c index 0a8bdade53f2..88df65d1e6f6 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -836,11 +836,29 @@ static struct kobject *get_device_parent(struct device *dev, return NULL; } +static inline bool live_in_glue_dir(struct kobject *kobj, + struct device *dev) +{ + if (!kobj || !dev->class || + kobj->kset != &dev->class->p->glue_dirs) + return false; + return true; +} + +static inline struct kobject *get_glue_dir(struct device *dev) +{ + return dev->kobj.parent; +} + +/* + * make sure cleaning up dir as the last step, we need to make + * sure .release handler of kobject is run with holding the + * global lock + */ static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) { /* see if we live in a "glue" directory */ - if (!glue_dir || !dev->class || - glue_dir->kset != &dev->class->p->glue_dirs) + if (!live_in_glue_dir(glue_dir, dev)) return; mutex_lock(&gdp_mutex); @@ -848,11 +866,6 @@ static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) mutex_unlock(&gdp_mutex); } -static void cleanup_device_parent(struct device *dev) -{ - cleanup_glue_dir(dev, dev->kobj.parent); -} - static int device_add_class_symlinks(struct device *dev) { struct device_node *of_node = dev_of_node(dev); @@ -1028,6 +1041,7 @@ int device_add(struct device *dev) struct kobject *kobj; struct class_interface *class_intf; int error = -EINVAL; + struct kobject *glue_dir = NULL; dev = get_device(dev); if (!dev) @@ -1072,8 +1086,10 @@ int device_add(struct device *dev) /* first, register with generic layer. */ /* we require the name to be set before, and pass NULL */ error = kobject_add(&dev->kobj, dev->kobj.parent, NULL); - if (error) + if (error) { + glue_dir = get_glue_dir(dev); goto Error; + } /* notify platform of device entry */ if (platform_notify) @@ -1154,9 +1170,10 @@ done: device_remove_file(dev, &dev_attr_uevent); attrError: kobject_uevent(&dev->kobj, KOBJ_REMOVE); + glue_dir = get_glue_dir(dev); kobject_del(&dev->kobj); Error: - cleanup_device_parent(dev); + cleanup_glue_dir(dev, glue_dir); put_device(parent); name_error: kfree(dev->p); @@ -1232,6 +1249,7 @@ EXPORT_SYMBOL_GPL(put_device); void device_del(struct device *dev) { struct device *parent = dev->parent; + struct kobject *glue_dir = NULL; struct class_interface *class_intf; /* Notify clients of device removal. This call must come @@ -1276,8 +1294,9 @@ void device_del(struct device *dev) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_REMOVED_DEVICE, dev); kobject_uevent(&dev->kobj, KOBJ_REMOVE); - cleanup_device_parent(dev); + glue_dir = get_glue_dir(dev); kobject_del(&dev->kobj); + cleanup_glue_dir(dev, glue_dir); put_device(parent); } EXPORT_SYMBOL_GPL(device_del); -- cgit v1.2.3-70-g09d2 From bea5b158ff0da9c7246ff391f754f5f38e34577a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 11 Aug 2016 10:20:58 -0500 Subject: driver core: add test of driver remove calls during probe In recent discussions on ksummit-discuss[1], it was suggested to do a sequence of probe, remove, probe for testing driver remove paths. This adds a kconfig option for said test. [1] https://lists.linuxfoundation.org/pipermail/ksummit-discuss/2016-August/003459.html Suggested-by: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/base/Kconfig | 10 ++++++++++ drivers/base/dd.c | 21 +++++++++++++++++++++ 2 files changed, 31 insertions(+) (limited to 'drivers/base') diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 98504ec99c7d..fdf44cac08e6 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -212,6 +212,16 @@ config DEBUG_DEVRES If you are unsure about this, Say N here. +config DEBUG_TEST_DRIVER_REMOVE + bool "Test driver remove calls during probe" + depends on DEBUG_KERNEL + help + Say Y here if you want the Driver core to test driver remove functions + by calling probe, remove, probe. This tests the remove path without + having to unbind the driver or unload the driver module. + + If you are unsure about this, say N here. + config SYS_HYPERVISOR bool default n diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 16688f50729c..4910e6db2a34 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -329,6 +329,7 @@ static int really_probe(struct device *dev, struct device_driver *drv) { int ret = -EPROBE_DEFER; int local_trigger_count = atomic_read(&deferred_trigger_count); + bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE); if (defer_all_probes) { /* @@ -346,6 +347,7 @@ static int really_probe(struct device *dev, struct device_driver *drv) drv->bus->name, __func__, drv->name, dev_name(dev)); WARN_ON(!list_empty(&dev->devres_head)); +re_probe: dev->driver = drv; /* If using pinctrl, bind pins now before probing */ @@ -383,6 +385,25 @@ static int really_probe(struct device *dev, struct device_driver *drv) goto probe_failed; } + if (test_remove) { + test_remove = false; + + if (dev->bus && dev->bus->remove) + dev->bus->remove(dev); + else if (drv->remove) + drv->remove(dev); + + devres_release_all(dev); + driver_sysfs_remove(dev); + dev->driver = NULL; + dev_set_drvdata(dev, NULL); + if (dev->pm_domain && dev->pm_domain->dismiss) + dev->pm_domain->dismiss(dev); + pm_runtime_reinit(dev); + + goto re_probe; + } + pinctrl_init_done(dev); if (dev->pm_domain && dev->pm_domain->sync) -- cgit v1.2.3-70-g09d2 From c90aab9c96c2a7f7bf3f7a54167dc5c0ba2b178c Mon Sep 17 00:00:00 2001 From: Jerome Marchand Date: Mon, 25 Jul 2016 16:13:32 +0200 Subject: platform driver: fix use-after-free in platform_device_del() In platform_device_del(), the device is still used after a call to device_del(). At this point there is no guarantee that the device is still there and there could be a use-after-free access. Move the call to device_remove_properties() before device_del() to fix that. Signed-off-by: Jerome Marchand Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 6482d47deb50..f57fff3f268b 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -434,6 +434,7 @@ void platform_device_del(struct platform_device *pdev) int i; if (pdev) { + device_remove_properties(&pdev->dev); device_del(&pdev->dev); if (pdev->id_auto) { @@ -446,8 +447,6 @@ void platform_device_del(struct platform_device *pdev) if (r->parent) release_resource(r); } - - device_remove_properties(&pdev->dev); } } EXPORT_SYMBOL_GPL(platform_device_del); -- cgit v1.2.3-70-g09d2 From 85714108e673cdebf1b96abfd50fb02a29e37577 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 21 Jul 2016 16:04:21 +0800 Subject: drivers: base: dma-mapping: page align the size when unmap_kernel_range When dma_common_free_remap, the input parameter 'size' may not be page aligned. And, met kernel warning when doing iommu dma for usb on i.MX8 platform: " WARNING: CPU: 0 PID: 869 at mm/vmalloc.c:70 vunmap_page_range+0x1cc/0x1d0() Modules linked in: CPU: 0 PID: 869 Comm: kworker/u8:2 Not tainted 4.1.12-00444-gc5f9d1d-dirty #147 Hardware name: Freescale i.MX8DV Sabreauto (DT) Workqueue: ci_otg ci_otg_work Call trace: [] dump_backtrace+0x0/0x124 [] show_stack+0x10/0x1c [] dump_stack+0x84/0xc8 [] warn_slowpath_common+0x98/0xd0 [] warn_slowpath_null+0x14/0x20 [] vunmap_page_range+0x1c8/0x1d0 [] unmap_kernel_range+0x20/0x88 [] dma_common_free_remap+0x74/0x84 [] __iommu_free_attrs+0x9c/0x178 [] ehci_mem_cleanup+0x140/0x194 [] ehci_stop+0x8c/0xdc [] usb_remove_hcd+0xf0/0x1cc [] host_stop+0x1c/0x58 [] ci_otg_work+0xdc/0x120 [] process_one_work+0x134/0x33c [] worker_thread+0x13c/0x47c [] kthread+0xd8/0xf0 " For dma_common_pages_remap: dma_common_pages_remap |->get_vm_area_caller |->__get_vm_area_node |->size = PAGE_ALIGN(size); Round up to page aligned So, in dma_common_free_remap, we also need a page aligned size, pass 'PAGE_ALIGN(size)' to unmap_kernel_range. Signed-off-by: Peng Fan Cc: Greg Kroah-Hartman Cc: Signed-off-by: Greg Kroah-Hartman --- drivers/base/dma-mapping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/base') diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c index d799662f19eb..261420ddfe66 100644 --- a/drivers/base/dma-mapping.c +++ b/drivers/base/dma-mapping.c @@ -334,7 +334,7 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags) return; } - unmap_kernel_range((unsigned long)cpu_addr, size); + unmap_kernel_range((unsigned long)cpu_addr, PAGE_ALIGN(size)); vunmap(cpu_addr); } #endif -- cgit v1.2.3-70-g09d2 From 426bc8e789f8ac84270b196191904d347586032f Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sun, 3 Jul 2016 14:22:51 -0400 Subject: base: soc: make it explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/base/Kconfig:config SOC_BUS drivers/base/Kconfig: bool ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. Since module_init was not in use by this code, the init ordering remains unchanged with this commit. Cc: Lee Jones Cc: Greg Kroah-Hartman Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman --- drivers/base/soc.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/soc.c b/drivers/base/soc.c index 75b98aad6faf..b63f23e6ad61 100644 --- a/drivers/base/soc.c +++ b/drivers/base/soc.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include @@ -160,11 +159,3 @@ static int __init soc_bus_register(void) return bus_register(&soc_bus_type); } core_initcall(soc_bus_register); - -static void __exit soc_bus_unregister(void) -{ - ida_destroy(&soc_ida); - - bus_unregister(&soc_bus_type); -} -module_exit(soc_bus_unregister); -- cgit v1.2.3-70-g09d2 From 03aca7b260ea2aadf92596d2f57160e4aee8ffb0 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Wed, 1 Jun 2016 09:18:40 +0800 Subject: attribute_container: Fix typo The 't' in "function" was missing, this patch fixes this typo: s/funcion/function/g Signed-off-by: Xiubo Li Signed-off-by: Greg Kroah-Hartman --- drivers/base/attribute_container.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/base') diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index 2ba4cac080c5..95e3ef82f3b7 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -243,7 +243,7 @@ attribute_container_remove_device(struct device *dev, * @dev: The generic device to run the trigger for * @fn the function to execute for each classdev. * - * This funcion is for executing a trigger when you need to know both + * This function is for executing a trigger when you need to know both * the container and the classdev. If you only care about the * container, then use attribute_container_trigger() instead. */ -- cgit v1.2.3-70-g09d2 From e688f144305c678fb65138d9e6b6ce436e59778b Mon Sep 17 00:00:00 2001 From: Muhammad Falak R Wani Date: Sat, 21 May 2016 18:52:57 +0530 Subject: drivers: dma-coherent: use vma_pages(). Replace explicit computation of vma page count by a call to vma_pages() Signed-off-by: Muhammad Falak R Wani Signed-off-by: Greg Kroah-Hartman --- drivers/base/dma-coherent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/base') diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c index bdf28f7dd5e8..db122a06edc5 100644 --- a/drivers/base/dma-coherent.c +++ b/drivers/base/dma-coherent.c @@ -261,7 +261,7 @@ int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma, (mem->virt_base + (mem->size << PAGE_SHIFT))) { unsigned long off = vma->vm_pgoff; int start = (vaddr - mem->virt_base) >> PAGE_SHIFT; - int user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + int user_count = vma_pages(vma); int count = size >> PAGE_SHIFT; *ret = -ENXIO; -- cgit v1.2.3-70-g09d2 From 95da00e35acf92bb5d39f6f08267de0c1a5c8885 Mon Sep 17 00:00:00 2001 From: Muhammad Falak R Wani Date: Sat, 21 May 2016 18:52:22 +0530 Subject: dma-mapping: use vma_pages(). Replace explicit computation of vma page count by a call to vma_pages() Signed-off-by: Muhammad Falak R Wani Signed-off-by: Greg Kroah-Hartman --- drivers/base/dma-mapping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/base') diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c index 261420ddfe66..2e318ffa019e 100644 --- a/drivers/base/dma-mapping.c +++ b/drivers/base/dma-mapping.c @@ -247,7 +247,7 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, { int ret = -ENXIO; #if defined(CONFIG_MMU) && !defined(CONFIG_ARCH_NO_COHERENT_DMA_MMAP) - unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + unsigned long user_count = vma_pages(vma); unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr)); unsigned long off = vma->vm_pgoff; -- cgit v1.2.3-70-g09d2 From 59fffa34069d80662b41438b11130771b4e2a897 Mon Sep 17 00:00:00 2001 From: Alex Shi Date: Thu, 25 Aug 2016 16:42:39 +0800 Subject: cpu: clean up register_cpu func This patch could reduce one branch in this function. Also make the code more readble. Signed-off-by: Alex Shi Acked-by: Daniel Lezcano To: linux-kernel@vger.kernel.org To: Greg Kroah-Hartman Cc: linux-pm@vger.kernel.org Cc: Ulf Hansson Cc: Daniel Lezcano Signed-off-by: Greg Kroah-Hartman --- drivers/base/cpu.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 691eeea2f19a..4c28e1a09786 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -371,12 +371,13 @@ int register_cpu(struct cpu *cpu, int num) if (cpu->hotpluggable) cpu->dev.groups = hotplugable_cpu_attr_groups; error = device_register(&cpu->dev); - if (!error) - per_cpu(cpu_sys_devices, num) = &cpu->dev; - if (!error) - register_cpu_under_node(num, cpu_to_node(num)); + if (error) + return error; - return error; + per_cpu(cpu_sys_devices, num) = &cpu->dev; + register_cpu_under_node(num, cpu_to_node(num)); + + return 0; } struct device *get_cpu_device(unsigned cpu) -- cgit v1.2.3-70-g09d2 From e330b9a6bb35dc7097a4f02cb1ae7b6f96df92af Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Mon, 4 Jul 2016 01:04:24 +0300 Subject: platform: don't return 0 from platform_get_irq[_byname]() on error of_irq_get[_byname]() return 0 iff irq_create_of_mapping() call fails. Returning both error code and 0 on failure is a sign of a misdesigned API, it makes the failure check unnecessarily complex and error prone. We should rely on the platform IRQ resource in this case, not return 0, especially as 0 can be a valid IRQ resource too... Fixes: aff008ad813c ("platform_get_irq: Revert to platform_get_resource if of_irq_get fails") Signed-off-by: Sergei Shtylyov CC: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index f57fff3f268b..44c9d4daf510 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -97,7 +97,7 @@ int platform_get_irq(struct platform_device *dev, unsigned int num) int ret; ret = of_irq_get(dev->dev.of_node, num); - if (ret >= 0 || ret == -EPROBE_DEFER) + if (ret > 0 || ret == -EPROBE_DEFER) return ret; } @@ -175,7 +175,7 @@ int platform_get_irq_byname(struct platform_device *dev, const char *name) int ret; ret = of_irq_get_byname(dev->dev.of_node, name); - if (ret >= 0 || ret == -EPROBE_DEFER) + if (ret > 0 || ret == -EPROBE_DEFER) return ret; } -- cgit v1.2.3-70-g09d2 From 775115c06091fcfa1189a50aca488fa596839617 Mon Sep 17 00:00:00 2001 From: "Vyacheslav V. Yurkov" Date: Tue, 14 Jun 2016 09:58:37 +0200 Subject: drivers/base dmam_declare_coherent_memory leaks dmam_declare_coherent_memory doesn't take into account the return value of dma_declare_coherent_memory, which leads to incorrect resource handling Signed-off-by: Vyacheslav V. Yurkov Signed-off-by: Greg Kroah-Hartman --- drivers/base/dma-mapping.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c index 2e318ffa019e..8f8b68c80986 100644 --- a/drivers/base/dma-mapping.c +++ b/drivers/base/dma-mapping.c @@ -198,10 +198,13 @@ int dmam_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, rc = dma_declare_coherent_memory(dev, phys_addr, device_addr, size, flags); - if (rc == 0) + if (rc) { devres_add(dev, res); - else + rc = 0; + } else { devres_free(res); + rc = -ENOMEM; + } return rc; } -- cgit v1.2.3-70-g09d2 From 2c507e464f791327c94d17a0137f00b4717744fc Mon Sep 17 00:00:00 2001 From: Bhaktipriya Shridhar Date: Tue, 30 Aug 2016 22:45:34 +0530 Subject: device core: Remove deprecated create_singlethread_workqueue The workqueue "deferred_wq" queues a single work item &deferred_probe_work and hence doesn't require ordering. It is involved in probing devices and is not being used on a memory reclaim path. Hence, it has been converted to use system_wq. System workqueues have been able to handle high level of concurrency for a long time now and hence it's not required to have a singlethreaded workqueue just to gain concurrency. Unlike a dedicated per-cpu workqueue created with create_singlethread_workqueue(), system_wq allows multiple work items to overlap executions even on the same CPU; however, a per-cpu workqueue doesn't have any CPU locality or global ordering guarantee unless the target CPU is explicitly specified and thus the increase of local concurrency shouldn't make any difference. The work item has been flushed in driver_probe_done() to ensure that there are no pending tasks while disconnecting the driver. Signed-off-by: Bhaktipriya Shridhar Acked-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 4910e6db2a34..d22a7260f42b 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -51,7 +51,6 @@ static DEFINE_MUTEX(deferred_probe_mutex); static LIST_HEAD(deferred_probe_pending_list); static LIST_HEAD(deferred_probe_active_list); -static struct workqueue_struct *deferred_wq; static atomic_t deferred_trigger_count = ATOMIC_INIT(0); /* @@ -175,7 +174,7 @@ static void driver_deferred_probe_trigger(void) * Kick the re-probe thread. It may already be scheduled, but it is * safe to kick it again. */ - queue_work(deferred_wq, &deferred_probe_work); + schedule_work(&deferred_probe_work); } /** @@ -211,14 +210,10 @@ void device_unblock_probing(void) */ static int deferred_probe_initcall(void) { - deferred_wq = create_singlethread_workqueue("deferwq"); - if (WARN_ON(!deferred_wq)) - return -ENOMEM; - driver_deferred_probe_enable = true; driver_deferred_probe_trigger(); /* Sort as many dependencies as possible before exiting initcalls */ - flush_workqueue(deferred_wq); + flush_work(&deferred_probe_work); return 0; } late_initcall(deferred_probe_initcall); @@ -481,8 +476,7 @@ int driver_probe_done(void) void wait_for_device_probe(void) { /* wait for the deferred probe workqueue to finish */ - if (driver_deferred_probe_enable) - flush_workqueue(deferred_wq); + flush_work(&deferred_probe_work); /* wait for the known devices to complete their probing */ wait_event(probe_waitqueue, atomic_read(&probe_count) == 0); -- cgit v1.2.3-70-g09d2 From 60ca5e0d280b1a51df55c5fc2e5bfe010b344c5a Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 13 Sep 2016 20:32:44 -0700 Subject: driver-core: platform: Catch errors from calls to irq_get_irq_data irq_get_irq_data() can return NULL, which results in a nasty crash. Check its return value before passing it on to irqd_set_trigger_type(). Signed-off-by: Guenter Roeck Reviewed-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 44c9d4daf510..c4af00385502 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -108,9 +108,14 @@ int platform_get_irq(struct platform_device *dev, unsigned int num) * IORESOURCE_BITS correspond 1-to-1 to the IRQF_TRIGGER* * settings. */ - if (r && r->flags & IORESOURCE_BITS) - irqd_set_trigger_type(irq_get_irq_data(r->start), - r->flags & IORESOURCE_BITS); + if (r && r->flags & IORESOURCE_BITS) { + struct irq_data *irqd; + + irqd = irq_get_irq_data(r->start); + if (!irqd) + return -ENXIO; + irqd_set_trigger_type(irqd, r->flags & IORESOURCE_BITS); + } return r ? r->start : -ENXIO; #endif -- cgit v1.2.3-70-g09d2 From 9ca5d4fd08d1c560a46ff649221a891065039891 Mon Sep 17 00:00:00 2001 From: "George G. Davis" Date: Wed, 28 Sep 2016 08:51:56 +0100 Subject: drivers: dma-coherent: Fix DMA coherent size for less than page We fix a bug in dma_mmap_from_coherent() that appears when we map non page aligned DMA memory. It cuts off the non aligned part (this is different to dma_alloc_coherent() that always rounds up to full pages). So for mappings of less than a page we get -ENXIO as dma_mmap_from_coherent() assumes we want to map zero pages. Signed-off-by: George G. Davis Signed-off-by: Jiada Wang Signed-off-by: Mark Craske Signed-off-by: Greg Kroah-Hartman --- drivers/base/dma-coherent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/base') diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c index db122a06edc5..2789f7a95b93 100644 --- a/drivers/base/dma-coherent.c +++ b/drivers/base/dma-coherent.c @@ -262,7 +262,7 @@ int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma, unsigned long off = vma->vm_pgoff; int start = (vaddr - mem->virt_base) >> PAGE_SHIFT; int user_count = vma_pages(vma); - int count = size >> PAGE_SHIFT; + int count = PAGE_ALIGN(size) >> PAGE_SHIFT; *ret = -ENXIO; if (off < count && user_count <= count - off) { -- cgit v1.2.3-70-g09d2 From dd01c75f1df311793de6ef217c72036552000c9a Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Wed, 28 Sep 2016 08:51:57 +0100 Subject: drivers: dma-coherent: Move spinlock in dma_alloc_from_coherent() We don't need to hold the spinlock while zeroing the allocated memory. In case we handle big buffers this is a severe issue as other CPUs might be spinning half a second or longer. Signed-off-by: Bastian Hecht Signed-off-by: George G. Davis Signed-off-by: Mark Craske Signed-off-by: Greg Kroah-Hartman --- drivers/base/dma-coherent.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c index 2789f7a95b93..640a7e63c453 100644 --- a/drivers/base/dma-coherent.c +++ b/drivers/base/dma-coherent.c @@ -165,6 +165,7 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size, int order = get_order(size); unsigned long flags; int pageno; + int dma_memory_map; if (!dev) return 0; @@ -187,11 +188,12 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size, */ *dma_handle = mem->device_base + (pageno << PAGE_SHIFT); *ret = mem->virt_base + (pageno << PAGE_SHIFT); - if (mem->flags & DMA_MEMORY_MAP) + dma_memory_map = (mem->flags & DMA_MEMORY_MAP); + spin_unlock_irqrestore(&mem->spinlock, flags); + if (dma_memory_map) memset(*ret, 0, size); else memset_io(*ret, 0, size); - spin_unlock_irqrestore(&mem->spinlock, flags); return 1; -- cgit v1.2.3-70-g09d2