From db81a82b6d3d00c576dc19f489c2bcd647b4b7f7 Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
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]  [<ffffffff8145be63>] dump_stack+0x54/0x8d
[    5.434413]  [<ffffffff8104b17d>] warn_slowpath_common+0x7d/0xa0
[    5.434417]  [<ffffffff8104b1ec>] warn_slowpath_fmt+0x4c/0x50
[    5.434421]  [<ffffffff81051fdc>] ? iomem_map_sanity_check+0xac/0xe0
[    5.434425]  [<ffffffff8103e8b3>] __ioremap_caller+0x2e3/0x390
[    5.434430]  [<ffffffff8103e9f2>] ioremap_wc+0x32/0x40
[    5.434450]  [<ffffffffa043f960>] i915_driver_load+0x670/0xf50 [i915]
[    5.434467]  [<ffffffff8131540d>] ? drm_get_minor+0x1ad/0x200
[    5.434471]  [<ffffffff81317509>] drm_get_pci_dev+0x129/0x2f0
[    5.434487]  [<ffffffffa043c63c>] i915_pci_probe+0x2c/0x70 [i915]
[    5.434493]  [<ffffffff8127f624>] pci_device_probe+0x84/0xe0
[    5.434502]  [<ffffffff81331977>] driver_probe_device+0x87/0x3a0
[    5.434509]  [<ffffffff81331d63>] __driver_attach+0x93/0xa0
[    5.434516]  [<ffffffff81331cd0>] ? __device_attach+0x40/0x40
[    5.434521]  [<ffffffff8132f813>] bus_for_each_dev+0x63/0xa0
[    5.434525]  [<ffffffff813313ce>] driver_attach+0x1e/0x20
[    5.434529]  [<ffffffff81330f40>] bus_add_driver+0x200/0x2d0
[    5.434533]  [<ffffffffa04dc000>] ? 0xffffffffa04dbfff
[    5.434538]  [<ffffffff813323e4>] driver_register+0x64/0xf0
[    5.434541]  [<ffffffffa04dc000>] ? 0xffffffffa04dbfff
[    5.434545]  [<ffffffff8127f45d>] __pci_register_driver+0x4d/0x50
[    5.434549]  [<ffffffff813177e5>] drm_pci_init+0x115/0x130
[    5.434552]  [<ffffffffa04dc000>] ? 0xffffffffa04dbfff
[    5.434567]  [<ffffffffa04dc066>] i915_init+0x66/0x68 [i915]
[    5.434570]  [<ffffffff8100022a>] do_one_initcall+0x5a/0x1b0
[    5.434575]  [<ffffffff81071588>] ? __blocking_notifier_call_chain+0x58/0x70
[    5.434581]  [<ffffffff810af52a>] load_module+0x1b0a/0x25a0
[    5.434584]  [<ffffffff810abf70>] ? store_uevent+0x40/0x40
[    5.434589]  [<ffffffff810b0136>] SyS_finit_module+0x86/0xb0
[    5.434594]  [<ffffffff81463da7>] tracesys+0xdd/0xe2
[    5.434599] ---[ end trace 4f93e77fcaaac9b7 ]---

Reported-by: Tom Gundersen <teg@jklm.no>
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 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

