diff options
Diffstat (limited to 'recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.1/0007-libertas-clean-up-scan-thread-handling.patch')
-rw-r--r-- | recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.1/0007-libertas-clean-up-scan-thread-handling.patch | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.1/0007-libertas-clean-up-scan-thread-handling.patch b/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.1/0007-libertas-clean-up-scan-thread-handling.patch new file mode 100644 index 00000000..38fbce3c --- /dev/null +++ b/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.1/0007-libertas-clean-up-scan-thread-handling.patch | |||
@@ -0,0 +1,86 @@ | |||
1 | From 3184baa0e69e6ad327808b91e0d915090c59b99b Mon Sep 17 00:00:00 2001 | ||
2 | From: Andres Salomon <dilinger@queued.net> | ||
3 | Date: Mon, 19 Dec 2011 12:22:58 -0800 | ||
4 | Subject: [PATCH 07/49] libertas: clean up scan thread handling | ||
5 | |||
6 | commit afbca95f95f2bf7283a72670c24c1f6de00b1cb5 upstream. | ||
7 | |||
8 | The libertas scan thread expects priv->scan_req to be non-NULL. In theory, | ||
9 | it should always be set. In practice, we've seen the following oops: | ||
10 | |||
11 | [ 8363.067444] Unable to handle kernel NULL pointer dereference at virtual address 00000004 | ||
12 | [ 8363.067490] pgd = c0004000 | ||
13 | [ 8363.078393] [00000004] *pgd=00000000 | ||
14 | [ 8363.086711] Internal error: Oops: 17 [#1] PREEMPT | ||
15 | [ 8363.091375] Modules linked in: fuse libertas_sdio libertas psmouse mousedev ov7670 mmp_camera joydev videobuf2_core videobuf2_dma_sg videobuf2_memops [last unloaded: scsi_wait_scan] | ||
16 | [ 8363.107490] CPU: 0 Not tainted (3.0.0-gf7ccc69 #671) | ||
17 | [ 8363.112799] PC is at lbs_scan_worker+0x108/0x5a4 [libertas] | ||
18 | [ 8363.118326] LR is at 0x0 | ||
19 | [ 8363.120836] pc : [<bf03a854>] lr : [<00000000>] psr: 60000113 | ||
20 | [ 8363.120845] sp : ee66bf48 ip : 00000000 fp : 00000000 | ||
21 | [ 8363.120845] r10: ee2c2088 r9 : c04e2efc r8 : eef97005 | ||
22 | [ 8363.132231] r7 : eee0716f r6 : ee2c02c0 r5 : ee2c2088 r4 : eee07160 | ||
23 | [ 8363.137419] r3 : 00000000 r2 : a0000113 r1 : 00000001 r0 : eee07160 | ||
24 | [ 8363.143896] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel | ||
25 | [ 8363.157630] Control: 10c5387d Table: 2e754019 DAC: 00000015 | ||
26 | [ 8363.163334] Process kworker/u:1 (pid: 25, stack limit = 0xee66a2f8) | ||
27 | |||
28 | While I've not found a smoking gun, there are two places that raised red flags | ||
29 | for me. The first is in _internal_start_scan, when we queue up a scan; we | ||
30 | first queue the worker, and then set priv->scan_req. There's theoretically | ||
31 | a 50mS delay which should be plenty, but doing things that way just seems | ||
32 | racy (and not in the good way). | ||
33 | |||
34 | The second is in the scan worker thread itself. Depending on the state of | ||
35 | priv->scan_channel, we cancel pending scan runs and then requeue a run in | ||
36 | 300mS. We then send the scan command down to the hardware, sleep, and if | ||
37 | we get scan results for all the desired channels, we set priv->scan_req to | ||
38 | NULL. However, it that's happened in less than 300mS, what happens with | ||
39 | the pending scan run? | ||
40 | |||
41 | This patch addresses both of those concerns. With the patch applied, we | ||
42 | have not seen the oops in the past two weeks. | ||
43 | |||
44 | Signed-off-by: Andres Salomon <dilinger@queued.net> | ||
45 | Signed-off-by: John W. Linville <linville@tuxdriver.com> | ||
46 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | ||
47 | --- | ||
48 | drivers/net/wireless/libertas/cfg.c | 10 ++++++---- | ||
49 | 1 files changed, 6 insertions(+), 4 deletions(-) | ||
50 | |||
51 | diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c | ||
52 | index a7f1ab2..db64ef1 100644 | ||
53 | --- a/drivers/net/wireless/libertas/cfg.c | ||
54 | +++ b/drivers/net/wireless/libertas/cfg.c | ||
55 | @@ -728,9 +728,11 @@ static void lbs_scan_worker(struct work_struct *work) | ||
56 | le16_to_cpu(scan_cmd->hdr.size), | ||
57 | lbs_ret_scan, 0); | ||
58 | |||
59 | - if (priv->scan_channel >= priv->scan_req->n_channels) | ||
60 | + if (priv->scan_channel >= priv->scan_req->n_channels) { | ||
61 | /* Mark scan done */ | ||
62 | + cancel_delayed_work(&priv->scan_work); | ||
63 | lbs_scan_done(priv); | ||
64 | + } | ||
65 | |||
66 | /* Restart network */ | ||
67 | if (carrier) | ||
68 | @@ -759,12 +761,12 @@ static void _internal_start_scan(struct lbs_private *priv, bool internal, | ||
69 | request->n_ssids, request->n_channels, request->ie_len); | ||
70 | |||
71 | priv->scan_channel = 0; | ||
72 | - queue_delayed_work(priv->work_thread, &priv->scan_work, | ||
73 | - msecs_to_jiffies(50)); | ||
74 | - | ||
75 | priv->scan_req = request; | ||
76 | priv->internal_scan = internal; | ||
77 | |||
78 | + queue_delayed_work(priv->work_thread, &priv->scan_work, | ||
79 | + msecs_to_jiffies(50)); | ||
80 | + | ||
81 | lbs_deb_leave(LBS_DEB_CFG80211); | ||
82 | } | ||
83 | |||
84 | -- | ||
85 | 1.7.7.4 | ||
86 | |||