From db81a82b6d3d00c576dc19f489c2bcd647b4b7f7 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sat, 7 Sep 2013 16:17:29 +0200 Subject: [PATCH 1/2] simplefb: fix unmapping fb during destruction Unfortunately, fbdev does not create its own "struct device" for framebuffers. Instead, it attaches to the device of the parent layer. This has the side-effect that devm_* managed resources are not cleaned up on framebuffer-destruction but rather during destruction of the parent-device. In case of fbdev this might be too late, though. Therefore, we now use plain ioremap() and unmap the framebuffer in the fb_destroy() callback. Note that we must not free the device here as this might race with the parent-device removal. Instead, we rely on unregister_framebuffer() as barrier and we're safe. This fixes a bug where remove_conflicting_framebuffer() removes a simplefb device on x86 which then misses to unmap the PCI BAR. The related WARN message is: [ 5.434312] ------------[ cut here ]------------ [ 5.434318] WARNING: CPU: 2 PID: 199 at arch/x86/mm/ioremap.c:171 __ioremap_caller+0x2e3/0x390() [ 5.434321] Info: mapping multiple BARs. Your kernel is fine. [ 5.434323] Modules linked in: [ 5.434326] [..snip..] [ 5.434383] CPU: 2 PID: 199 Comm: systemd-udevd Not tainted 3.11.0-TEG-05060-g0312d0c #81 [ 5.434386] Hardware name: Apple Inc. MacBookAir5,1/Mac-66F35F19FE2A0D05, BIOS MBA51.88Z.00EF.B01.1207271122 07/27/2012 [ 5.434390] 0000000000000009 ffff880168f87898 ffffffff8145be63 ffff880168f878e0 [ 5.434394] ffff880168f878d0 ffffffff8104b17d ffffc9000c080000 00000000a0000000 [ 5.434398] ffffc9000c080000 ffffc9000c080000 0000000010000000 ffff880168f87930 [ 5.434403] Call Trace: [ 5.434409] [] dump_stack+0x54/0x8d [ 5.434413] [] warn_slowpath_common+0x7d/0xa0 [ 5.434417] [] warn_slowpath_fmt+0x4c/0x50 [ 5.434421] [] ? iomem_map_sanity_check+0xac/0xe0 [ 5.434425] [] __ioremap_caller+0x2e3/0x390 [ 5.434430] [] ioremap_wc+0x32/0x40 [ 5.434450] [] i915_driver_load+0x670/0xf50 [i915] [ 5.434467] [] ? drm_get_minor+0x1ad/0x200 [ 5.434471] [] drm_get_pci_dev+0x129/0x2f0 [ 5.434487] [] i915_pci_probe+0x2c/0x70 [i915] [ 5.434493] [] pci_device_probe+0x84/0xe0 [ 5.434502] [] driver_probe_device+0x87/0x3a0 [ 5.434509] [] __driver_attach+0x93/0xa0 [ 5.434516] [] ? __device_attach+0x40/0x40 [ 5.434521] [] bus_for_each_dev+0x63/0xa0 [ 5.434525] [] driver_attach+0x1e/0x20 [ 5.434529] [] bus_add_driver+0x200/0x2d0 [ 5.434533] [] ? 0xffffffffa04dbfff [ 5.434538] [] driver_register+0x64/0xf0 [ 5.434541] [] ? 0xffffffffa04dbfff [ 5.434545] [] __pci_register_driver+0x4d/0x50 [ 5.434549] [] drm_pci_init+0x115/0x130 [ 5.434552] [] ? 0xffffffffa04dbfff [ 5.434567] [] i915_init+0x66/0x68 [i915] [ 5.434570] [] do_one_initcall+0x5a/0x1b0 [ 5.434575] [] ? __blocking_notifier_call_chain+0x58/0x70 [ 5.434581] [] load_module+0x1b0a/0x25a0 [ 5.434584] [] ? store_uevent+0x40/0x40 [ 5.434589] [] SyS_finit_module+0x86/0xb0 [ 5.434594] [] tracesys+0xdd/0xe2 [ 5.434599] ---[ end trace 4f93e77fcaaac9b7 ]--- Reported-by: Tom Gundersen Signed-off-by: David Herrmann --- drivers/video/simplefb.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c index 8d78106..74b016c 100644 --- a/drivers/video/simplefb.c +++ b/drivers/video/simplefb.c @@ -66,8 +66,15 @@ static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, return 0; } +static void simplefb_destroy(struct fb_info *info) +{ + if (info->screen_base) + iounmap(info->screen_base); +} + static struct fb_ops simplefb_ops = { .owner = THIS_MODULE, + .fb_destroy = simplefb_destroy, .fb_setcolreg = simplefb_setcolreg, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, @@ -212,8 +219,8 @@ static int simplefb_probe(struct platform_device *pdev) info->fbops = &simplefb_ops; info->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE; - info->screen_base = devm_ioremap(&pdev->dev, info->fix.smem_start, - info->fix.smem_len); + info->screen_base = ioremap(info->fix.smem_start, + info->fix.smem_len); if (!info->screen_base) { framebuffer_release(info); return -ENODEV; @@ -223,6 +230,7 @@ static int simplefb_probe(struct platform_device *pdev) ret = register_framebuffer(info); if (ret < 0) { dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret); + iounmap(info->screen_base); framebuffer_release(info); return ret; } -- 1.8.4