aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArend van Spriel <arend@broadcom.com>2013-09-25 06:11:01 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-09-26 14:02:33 -0400
commitdb4efbbeb457b6f9f4d8c4b090d1170d12f026e1 (patch)
tree6bf71d871fb6d35956551bdd813de4eaba0f0e4e
parent346ece0b7ba2730b4d633b9e371fe55488803102 (diff)
brcmfmac: obtain platform data upon module initialization
The driver uses platform_driver_probe() to obtain platform data if any. However, that function is placed in the .init section so it must be called upon driver module initialization. The problem was reported by Fenguang Wu resulting in a kernel oops because the .init section was already freed. [ 48.966342] Switched to clocksource tsc [ 48.970002] kernel tried to execute NX-protected page - exploit attempt? (uid: 0) [ 48.970851] BUG: unable to handle kernel paging request at ffffffff82196446 [ 48.970957] IP: [<ffffffff82196446>] classes_init+0x26/0x26 [ 48.970957] PGD 1e76067 PUD 1e77063 PMD f388063 PTE 8000000002196163 [ 48.970957] Oops: 0011 [#1] [ 48.970957] CPU: 0 PID: 17 Comm: kworker/0:1 Not tainted 3.11.0-rc7-00444-gc52dd7f #23 [ 48.970957] Workqueue: events brcmf_driver_init [ 48.970957] task: ffff8800001d2000 ti: ffff8800001d4000 task.ti: ffff8800001d4000 [ 48.970957] RIP: 0010:[<ffffffff82196446>] [<ffffffff82196446>] classes_init+0x26/0x26 [ 48.970957] RSP: 0000:ffff8800001d5d40 EFLAGS: 00000286 [ 48.970957] RAX: 0000000000000001 RBX: ffffffff820c5620 RCX: 0000000000000000 [ 48.970957] RDX: 0000000000000001 RSI: ffffffff816f7380 RDI: ffffffff820c56c0 [ 48.970957] RBP: ffff8800001d5d50 R08: ffff8800001d2508 R09: 0000000000000002 [ 48.970957] R10: 0000000000000000 R11: 0001f7ce298c5620 R12: ffff8800001c76b0 [ 48.970957] R13: ffffffff81e91d40 R14: 0000000000000000 R15: ffff88000e0ce300 [ 48.970957] FS: 0000000000000000(0000) GS:ffffffff81e84000(0000) knlGS:0000000000000000 [ 48.970957] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 48.970957] CR2: ffffffff82196446 CR3: 0000000001e75000 CR4: 00000000000006b0 [ 48.970957] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 48.970957] DR3: 0000000000000000 DR6: 0000000000000000 DR7: 0000000000000000 [ 48.970957] Stack: [ 48.970957] ffffffff816f7df8 ffffffff820c5620 ffff8800001d5d60 ffffffff816eeec9 [ 48.970957] ffff8800001d5de0 ffffffff81073dc5 ffffffff81073d68 ffff8800001d5db8 [ 48.970957] 0000000000000086 ffffffff820c5620 ffffffff824f7fd0 0000000000000000 [ 48.970957] Call Trace: [ 48.970957] [<ffffffff816f7df8>] ? brcmf_sdio_init+0x18/0x70 [ 48.970957] [<ffffffff816eeec9>] brcmf_driver_init+0x9/0x10 [ 48.970957] [<ffffffff81073dc5>] process_one_work+0x1d5/0x480 [ 48.970957] [<ffffffff81073d68>] ? process_one_work+0x178/0x480 [ 48.970957] [<ffffffff81074188>] worker_thread+0x118/0x3a0 [ 48.970957] [<ffffffff81074070>] ? process_one_work+0x480/0x480 [ 48.970957] [<ffffffff8107aa17>] kthread+0xe7/0xf0 [ 48.970957] [<ffffffff810829f7>] ? finish_task_switch.constprop.57+0x37/0xd0 [ 48.970957] [<ffffffff8107a930>] ? __kthread_parkme+0x80/0x80 [ 48.970957] [<ffffffff81a6923a>] ret_from_fork+0x7a/0xb0 [ 48.970957] [<ffffffff8107a930>] ? __kthread_parkme+0x80/0x80 [ 48.970957] Code: cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc <cc> cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc [ 48.970957] RIP [<ffffffff82196446>] classes_init+0x26/0x26 [ 48.970957] RSP <ffff8800001d5d40> [ 48.970957] CR2: ffffffff82196446 [ 48.970957] ---[ end trace 62980817cd525f14 ]--- Cc: <stable@vger.kernel.org> # 3.10.x, 3.11.x Reported-by: Fengguang Wu <fengguang.wu@intel.com> Reviewed-by: Hante Meuleman <meuleman@broadcom.com> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Tested-by: Fengguang Wu <fengguang.wu@intel.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c28
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h3
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c14
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.c2
4 files changed, 24 insertions, 23 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
index 64f4a2bc8dde..c3462b75bd08 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
@@ -464,8 +464,6 @@ static struct sdio_driver brcmf_sdmmc_driver = {
464 464
465static int brcmf_sdio_pd_probe(struct platform_device *pdev) 465static int brcmf_sdio_pd_probe(struct platform_device *pdev)
466{ 466{
467 int ret;
468
469 brcmf_dbg(SDIO, "Enter\n"); 467 brcmf_dbg(SDIO, "Enter\n");
470 468
471 brcmfmac_sdio_pdata = pdev->dev.platform_data; 469 brcmfmac_sdio_pdata = pdev->dev.platform_data;
@@ -473,11 +471,7 @@ static int brcmf_sdio_pd_probe(struct platform_device *pdev)
473 if (brcmfmac_sdio_pdata->power_on) 471 if (brcmfmac_sdio_pdata->power_on)
474 brcmfmac_sdio_pdata->power_on(); 472 brcmfmac_sdio_pdata->power_on();
475 473
476 ret = sdio_register_driver(&brcmf_sdmmc_driver); 474 return 0;
477 if (ret)
478 brcmf_err("sdio_register_driver failed: %d\n", ret);
479
480 return ret;
481} 475}
482 476
483static int brcmf_sdio_pd_remove(struct platform_device *pdev) 477static int brcmf_sdio_pd_remove(struct platform_device *pdev)
@@ -500,6 +494,15 @@ static struct platform_driver brcmf_sdio_pd = {
500 } 494 }
501}; 495};
502 496
497void brcmf_sdio_register(void)
498{
499 int ret;
500
501 ret = sdio_register_driver(&brcmf_sdmmc_driver);
502 if (ret)
503 brcmf_err("sdio_register_driver failed: %d\n", ret);
504}
505
503void brcmf_sdio_exit(void) 506void brcmf_sdio_exit(void)
504{ 507{
505 brcmf_dbg(SDIO, "Enter\n"); 508 brcmf_dbg(SDIO, "Enter\n");
@@ -510,18 +513,13 @@ void brcmf_sdio_exit(void)
510 sdio_unregister_driver(&brcmf_sdmmc_driver); 513 sdio_unregister_driver(&brcmf_sdmmc_driver);
511} 514}
512 515
513void brcmf_sdio_init(void) 516void __init brcmf_sdio_init(void)
514{ 517{
515 int ret; 518 int ret;
516 519
517 brcmf_dbg(SDIO, "Enter\n"); 520 brcmf_dbg(SDIO, "Enter\n");
518 521
519 ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe); 522 ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe);
520 if (ret == -ENODEV) { 523 if (ret == -ENODEV)
521 brcmf_dbg(SDIO, "No platform data available, registering without.\n"); 524 brcmf_dbg(SDIO, "No platform data available.\n");
522 ret = sdio_register_driver(&brcmf_sdmmc_driver);
523 }
524
525 if (ret)
526 brcmf_err("driver registration failed: %d\n", ret);
527} 525}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
index f7c1985844e4..74156f84180c 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
@@ -156,10 +156,11 @@ extern int brcmf_bus_start(struct device *dev);
156#ifdef CONFIG_BRCMFMAC_SDIO 156#ifdef CONFIG_BRCMFMAC_SDIO
157extern void brcmf_sdio_exit(void); 157extern void brcmf_sdio_exit(void);
158extern void brcmf_sdio_init(void); 158extern void brcmf_sdio_init(void);
159extern void brcmf_sdio_register(void);
159#endif 160#endif
160#ifdef CONFIG_BRCMFMAC_USB 161#ifdef CONFIG_BRCMFMAC_USB
161extern void brcmf_usb_exit(void); 162extern void brcmf_usb_exit(void);
162extern void brcmf_usb_init(void); 163extern void brcmf_usb_register(void);
163#endif 164#endif
164 165
165#endif /* _BRCMF_BUS_H_ */ 166#endif /* _BRCMF_BUS_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index e067aec1fbf1..40e7f854e10f 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -1231,21 +1231,23 @@ u32 brcmf_get_chip_info(struct brcmf_if *ifp)
1231 return bus->chip << 4 | bus->chiprev; 1231 return bus->chip << 4 | bus->chiprev;
1232} 1232}
1233 1233
1234static void brcmf_driver_init(struct work_struct *work) 1234static void brcmf_driver_register(struct work_struct *work)
1235{ 1235{
1236 brcmf_debugfs_init();
1237
1238#ifdef CONFIG_BRCMFMAC_SDIO 1236#ifdef CONFIG_BRCMFMAC_SDIO
1239 brcmf_sdio_init(); 1237 brcmf_sdio_register();
1240#endif 1238#endif
1241#ifdef CONFIG_BRCMFMAC_USB 1239#ifdef CONFIG_BRCMFMAC_USB
1242 brcmf_usb_init(); 1240 brcmf_usb_register();
1243#endif 1241#endif
1244} 1242}
1245static DECLARE_WORK(brcmf_driver_work, brcmf_driver_init); 1243static DECLARE_WORK(brcmf_driver_work, brcmf_driver_register);
1246 1244
1247static int __init brcmfmac_module_init(void) 1245static int __init brcmfmac_module_init(void)
1248{ 1246{
1247 brcmf_debugfs_init();
1248#ifdef CONFIG_BRCMFMAC_SDIO
1249 brcmf_sdio_init();
1250#endif
1249 if (!schedule_work(&brcmf_driver_work)) 1251 if (!schedule_work(&brcmf_driver_work))
1250 return -EBUSY; 1252 return -EBUSY;
1251 1253
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
index 39e01a7c8556..f4aea47e0730 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -1539,7 +1539,7 @@ void brcmf_usb_exit(void)
1539 brcmf_release_fw(&fw_image_list); 1539 brcmf_release_fw(&fw_image_list);
1540} 1540}
1541 1541
1542void brcmf_usb_init(void) 1542void brcmf_usb_register(void)
1543{ 1543{
1544 brcmf_dbg(USB, "Enter\n"); 1544 brcmf_dbg(USB, "Enter\n");
1545 INIT_LIST_HEAD(&fw_image_list); 1545 INIT_LIST_HEAD(&fw_image_list);