diff options
author | Bob Copeland <me@bobcopeland.com> | 2009-08-07 06:33:49 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-14 09:13:38 -0400 |
commit | b5ed9c1b6f8fcb2d2315f12599fd5808f7933f16 (patch) | |
tree | 33f56a3d843dc59b7643a28ea3e5916a7ac7d362 /drivers/net/wireless/wl12xx | |
parent | 3ec410d747fa1da035183c43775a64c0e285e399 (diff) |
wl1251: make irq handling interface specific
In SDIO, the host driver requests the IRQ and invokes a callback to the
card driver. This differs from SPI, so the relevant code needs to be
interface-specific. This patch pushes the irq code down into _spi.c
and _sdio.c, and adds enable/disable callbacks.
This fixes the following warning:
[ 566.343887] ------------[ cut here ]------------
[ 566.349105] WARNING: at kernel/irq/manage.c:222 __enable_irq+0x3c/0x6c()
[ 566.356735] Unbalanced enable for IRQ 0
[ 566.361099] Modules linked in: msm_wifi wl12xx_sdio wl12xx mac80211 cfg80211 rfkill_backport lib80211_crypt_ccmp lib80211_crypt_wep lib80211_crypt_tkip lib80211
[ 566.381240] [<c025acec>] (dump_stack+0x0/0x14) from [<c004b610>] (warn_slowpath+0x70/0x8c)
[ 566.391860] [<c004b5a0>] (warn_slowpath+0x0/0x8c) from [<c0077c10>] (__enable_irq+0x3c/0x6c)
[ 566.402572] r3:00000000 r2:c02cad13
[ 566.407516] r7:00001002 r6:00000000 r5:c0310be4 r4:c0310be4
[ 566.415786] [<c0077bd4>] (__enable_irq+0x0/0x6c) from [<c0077fd0>] (enable_irq+0x38/0x64)
[ 566.425826] r5:c0310be4 r4:a0000013
[ 566.430709] [<c0077f98>] (enable_irq+0x0/0x64) from [<bf0dfa78>] (wl12xx_boot_run_firmware+0xfc/0x170 [wl12xx])
[ 566.442947] r7:00001002 r6:c440a9fc r5:00000072 r4:c440a9e0
[ 566.450851] [<bf0df97c>] (wl12xx_boot_run_firmware+0x0/0x170 [wl12xx]) from [<bf0e05f0>] (wl1251_boot+0xd4/0x108 [wl12xx])
[ 566.464492] r5:00000000 r4:c440a9e0
[ 566.469466] [<bf0e051c>] (wl1251_boot+0x0/0x108 [wl12xx]) from [<bf0dd27c>] (wl12xx_op_start+0x54/0xb8 [wl12xx])
[ 566.482162] r5:00000000 r4:c440a9e0
[ 566.487472] [<bf0dd228>] (wl12xx_op_start+0x0/0xb8 [wl12xx]) from [<bf0b96dc>] (ieee80211_open+0x2dc/0x720 [mac80211])
[ 566.500594] r7:00001002 r6:c4950800 r5:c440a220 r4:00000000
[ 566.508865] [<bf0b9400>] (ieee80211_open+0x0/0x720 [mac80211]) from [<c01f1edc>] (dev_open+0x9c/0xfc)
[ 566.520705] [<c01f1e40>] (dev_open+0x0/0xfc) from [<c01f17dc>] (dev_change_flags+0x98/0x170)
[ 566.531417] r5:00000041 r4:c4950800
[ 566.536330] [<c01f1744>] (dev_change_flags+0x0/0x170) from [<c023041c>] (devinet_ioctl+0x3a8/0x784)
[ 566.547683] r7:c128e380 r6:00000001 r5:00008914 r4:00000000
[ 566.555587] [<c0230074>] (devinet_ioctl+0x0/0x784) from [<c02318cc>] (inet_ioctl+0xdc/0x114)
[ 566.566299] [<c02317f0>] (inet_ioctl+0x0/0x114) from [<c01e1a60>] (sock_ioctl+0x1f0/0x248)
[ 566.576827] r5:00008914 r4:c572c1a0
[ 566.581771] [<c01e1870>] (sock_ioctl+0x0/0x248) from [<c00b23a0>] (vfs_ioctl+0x34/0x94)
[ 566.592086] r7:c572c1a0 r6:bee497e8 r5:00008914 r4:c572c1a0
[ 566.599990] [<c00b236c>] (vfs_ioctl+0x0/0x94) from [<c00b2a28>] (do_vfs_ioctl+0x52c/0x584)
[ 566.610549] r7:c572c1a0 r6:00008914 r5:c572c1a0 r4:c3201228
[ 566.618453] [<c00b24fc>] (do_vfs_ioctl+0x0/0x584) from [<c00b2ac0>] (sys_ioctl+0x40/0x64)
[ 566.628890] [<c00b2a80>] (sys_ioctl+0x0/0x64) from [<c0021da0>] (ret_fast_syscall+0x0/0x2c)
[ 566.639541] r7:00000036 r6:00000000 r5:00000004 r4:001a11f3
[ 566.647445] ---[ end trace 15c26ef7dd5e7b03 ]---
Signed-off-by: Bob Copeland <me@bobcopeland.com>
Signed-off-by: Kalle Valo <kalle.valo@nokia.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251.h | 5 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_boot.c | 7 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_main.c | 24 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_sdio.c | 36 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_spi.c | 26 |
5 files changed, 65 insertions, 33 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index ebe2c70559cd..13f0589beec9 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h | |||
@@ -285,6 +285,8 @@ struct wl1251_if_operations { | |||
285 | void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len); | 285 | void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len); |
286 | void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len); | 286 | void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len); |
287 | void (*reset)(struct wl1251 *wl); | 287 | void (*reset)(struct wl1251 *wl); |
288 | void (*enable_irq)(struct wl1251 *wl); | ||
289 | void (*disable_irq)(struct wl1251 *wl); | ||
288 | }; | 290 | }; |
289 | 291 | ||
290 | struct wl1251 { | 292 | struct wl1251 { |
@@ -404,10 +406,11 @@ struct wl1251 { | |||
404 | int wl1251_plt_start(struct wl1251 *wl); | 406 | int wl1251_plt_start(struct wl1251 *wl); |
405 | int wl1251_plt_stop(struct wl1251 *wl); | 407 | int wl1251_plt_stop(struct wl1251 *wl); |
406 | 408 | ||
407 | irqreturn_t wl1251_irq(int irq, void *cookie); | ||
408 | struct ieee80211_hw *wl1251_alloc_hw(void); | 409 | struct ieee80211_hw *wl1251_alloc_hw(void); |
409 | int wl1251_free_hw(struct wl1251 *wl); | 410 | int wl1251_free_hw(struct wl1251 *wl); |
410 | int wl1251_init_ieee80211(struct wl1251 *wl); | 411 | int wl1251_init_ieee80211(struct wl1251 *wl); |
412 | void wl1251_enable_interrupts(struct wl1251 *wl); | ||
413 | void wl1251_disable_interrupts(struct wl1251 *wl); | ||
411 | 414 | ||
412 | #define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ | 415 | #define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ |
413 | #define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS | 416 | #define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS |
diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index 5c6f32757ac4..8b50d44d8243 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c | |||
@@ -29,11 +29,6 @@ | |||
29 | #include "wl1251_spi.h" | 29 | #include "wl1251_spi.h" |
30 | #include "wl1251_event.h" | 30 | #include "wl1251_event.h" |
31 | 31 | ||
32 | static void wl1251_boot_enable_interrupts(struct wl1251 *wl) | ||
33 | { | ||
34 | enable_irq(wl->irq); | ||
35 | } | ||
36 | |||
37 | void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) | 32 | void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) |
38 | { | 33 | { |
39 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); | 34 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); |
@@ -278,7 +273,7 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) | |||
278 | */ | 273 | */ |
279 | 274 | ||
280 | /* enable gpio interrupts */ | 275 | /* enable gpio interrupts */ |
281 | wl1251_boot_enable_interrupts(wl); | 276 | wl1251_enable_interrupts(wl); |
282 | 277 | ||
283 | wl->chip.op_target_enable_interrupts(wl); | 278 | wl->chip.op_target_enable_interrupts(wl); |
284 | 279 | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index abe157a174c7..4c1aad33fb51 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c | |||
@@ -42,9 +42,14 @@ | |||
42 | #include "wl1251_init.h" | 42 | #include "wl1251_init.h" |
43 | #include "wl1251_debugfs.h" | 43 | #include "wl1251_debugfs.h" |
44 | 44 | ||
45 | static void wl1251_disable_interrupts(struct wl1251 *wl) | 45 | void wl1251_enable_interrupts(struct wl1251 *wl) |
46 | { | 46 | { |
47 | disable_irq(wl->irq); | 47 | wl->if_ops->enable_irq(wl); |
48 | } | ||
49 | |||
50 | void wl1251_disable_interrupts(struct wl1251 *wl) | ||
51 | { | ||
52 | wl->if_ops->disable_irq(wl); | ||
48 | } | 53 | } |
49 | 54 | ||
50 | static void wl1251_power_off(struct wl1251 *wl) | 55 | static void wl1251_power_off(struct wl1251 *wl) |
@@ -57,20 +62,6 @@ static void wl1251_power_on(struct wl1251 *wl) | |||
57 | wl->set_power(true); | 62 | wl->set_power(true); |
58 | } | 63 | } |
59 | 64 | ||
60 | irqreturn_t wl1251_irq(int irq, void *cookie) | ||
61 | { | ||
62 | struct wl1251 *wl; | ||
63 | |||
64 | wl1251_debug(DEBUG_IRQ, "IRQ"); | ||
65 | |||
66 | wl = cookie; | ||
67 | |||
68 | schedule_work(&wl->irq_work); | ||
69 | |||
70 | return IRQ_HANDLED; | ||
71 | } | ||
72 | EXPORT_SYMBOL_GPL(wl1251_irq); | ||
73 | |||
74 | static int wl1251_fetch_firmware(struct wl1251 *wl) | 65 | static int wl1251_fetch_firmware(struct wl1251 *wl) |
75 | { | 66 | { |
76 | const struct firmware *fw; | 67 | const struct firmware *fw; |
@@ -1280,7 +1271,6 @@ int wl1251_free_hw(struct wl1251 *wl) | |||
1280 | 1271 | ||
1281 | wl1251_debugfs_exit(wl); | 1272 | wl1251_debugfs_exit(wl); |
1282 | 1273 | ||
1283 | free_irq(wl->irq, wl); | ||
1284 | kfree(wl->target_mem_map); | 1274 | kfree(wl->target_mem_map); |
1285 | kfree(wl->data_path); | 1275 | kfree(wl->data_path); |
1286 | kfree(wl->fw); | 1276 | kfree(wl->fw); |
diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c index f1d9e76e0484..f7e451fed8b5 100644 --- a/drivers/net/wireless/wl12xx/wl1251_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c | |||
@@ -50,7 +50,12 @@ static struct sdio_func *wl_to_func(struct wl1251 *wl) | |||
50 | 50 | ||
51 | static void wl1251_sdio_interrupt(struct sdio_func *func) | 51 | static void wl1251_sdio_interrupt(struct sdio_func *func) |
52 | { | 52 | { |
53 | wl1251_irq(0, sdio_get_drvdata(func)); | 53 | struct wl1251 *wl = sdio_get_drvdata(func); |
54 | |||
55 | wl1251_debug(DEBUG_IRQ, "IRQ"); | ||
56 | |||
57 | /* FIXME should be synchronous for sdio */ | ||
58 | schedule_work(&wl->irq_work); | ||
54 | } | 59 | } |
55 | 60 | ||
56 | static const struct sdio_device_id wl1251_devices[] = { | 61 | static const struct sdio_device_id wl1251_devices[] = { |
@@ -88,6 +93,24 @@ void wl1251_sdio_reset(struct wl1251 *wl) | |||
88 | { | 93 | { |
89 | } | 94 | } |
90 | 95 | ||
96 | static void wl1251_sdio_enable_irq(struct wl1251 *wl) | ||
97 | { | ||
98 | struct sdio_func *func = wl_to_func(wl); | ||
99 | |||
100 | sdio_claim_host(func); | ||
101 | sdio_claim_irq(func, wl1251_sdio_interrupt); | ||
102 | sdio_release_host(func); | ||
103 | } | ||
104 | |||
105 | static void wl1251_sdio_disable_irq(struct wl1251 *wl) | ||
106 | { | ||
107 | struct sdio_func *func = wl_to_func(wl); | ||
108 | |||
109 | sdio_claim_host(func); | ||
110 | sdio_release_irq(func); | ||
111 | sdio_release_host(func); | ||
112 | } | ||
113 | |||
91 | void wl1251_sdio_set_power(bool enable) | 114 | void wl1251_sdio_set_power(bool enable) |
92 | { | 115 | { |
93 | } | 116 | } |
@@ -96,6 +119,8 @@ struct wl1251_if_operations wl1251_sdio_ops = { | |||
96 | .read = wl1251_sdio_read, | 119 | .read = wl1251_sdio_read, |
97 | .write = wl1251_sdio_write, | 120 | .write = wl1251_sdio_write, |
98 | .reset = wl1251_sdio_reset, | 121 | .reset = wl1251_sdio_reset, |
122 | .enable_irq = wl1251_sdio_enable_irq, | ||
123 | .disable_irq = wl1251_sdio_disable_irq, | ||
99 | }; | 124 | }; |
100 | 125 | ||
101 | int wl1251_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) | 126 | int wl1251_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) |
@@ -124,21 +149,14 @@ int wl1251_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) | |||
124 | 149 | ||
125 | sdio_release_host(func); | 150 | sdio_release_host(func); |
126 | ret = wl1251_init_ieee80211(wl); | 151 | ret = wl1251_init_ieee80211(wl); |
127 | sdio_claim_host(func); | ||
128 | if (ret) | 152 | if (ret) |
129 | goto disable; | 153 | goto disable; |
130 | 154 | ||
131 | ret = sdio_claim_irq(func, wl1251_sdio_interrupt); | ||
132 | if (ret) | ||
133 | goto no_irq; | ||
134 | |||
135 | sdio_release_host(func); | ||
136 | sdio_set_drvdata(func, wl); | 155 | sdio_set_drvdata(func, wl); |
137 | return ret; | 156 | return ret; |
138 | 157 | ||
139 | no_irq: | ||
140 | wl1251_free_hw(wl); | ||
141 | disable: | 158 | disable: |
159 | sdio_claim_host(func); | ||
142 | sdio_disable_func(func); | 160 | sdio_disable_func(func); |
143 | release: | 161 | release: |
144 | sdio_release_host(func); | 162 | sdio_release_host(func); |
diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index 5967317ef025..7d1031b7a088 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c | |||
@@ -31,6 +31,19 @@ | |||
31 | #include "reg.h" | 31 | #include "reg.h" |
32 | #include "wl1251_spi.h" | 32 | #include "wl1251_spi.h" |
33 | 33 | ||
34 | static irqreturn_t wl1251_irq(int irq, void *cookie) | ||
35 | { | ||
36 | struct wl1251 *wl; | ||
37 | |||
38 | wl1251_debug(DEBUG_IRQ, "IRQ"); | ||
39 | |||
40 | wl = cookie; | ||
41 | |||
42 | schedule_work(&wl->irq_work); | ||
43 | |||
44 | return IRQ_HANDLED; | ||
45 | } | ||
46 | |||
34 | static struct spi_device *wl_to_spi(struct wl1251 *wl) | 47 | static struct spi_device *wl_to_spi(struct wl1251 *wl) |
35 | { | 48 | { |
36 | return wl->if_priv; | 49 | return wl->if_priv; |
@@ -193,10 +206,22 @@ static void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, | |||
193 | wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); | 206 | wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); |
194 | } | 207 | } |
195 | 208 | ||
209 | static void wl1251_spi_enable_irq(struct wl1251 *wl) | ||
210 | { | ||
211 | return enable_irq(wl->irq); | ||
212 | } | ||
213 | |||
214 | static void wl1251_spi_disable_irq(struct wl1251 *wl) | ||
215 | { | ||
216 | return disable_irq(wl->irq); | ||
217 | } | ||
218 | |||
196 | static const struct wl1251_if_operations wl1251_spi_ops = { | 219 | static const struct wl1251_if_operations wl1251_spi_ops = { |
197 | .read = wl1251_spi_read, | 220 | .read = wl1251_spi_read, |
198 | .write = wl1251_spi_write, | 221 | .write = wl1251_spi_write, |
199 | .reset = wl1251_spi_reset_wake, | 222 | .reset = wl1251_spi_reset_wake, |
223 | .enable_irq = wl1251_spi_enable_irq, | ||
224 | .disable_irq = wl1251_spi_disable_irq, | ||
200 | }; | 225 | }; |
201 | 226 | ||
202 | static int __devinit wl1251_spi_probe(struct spi_device *spi) | 227 | static int __devinit wl1251_spi_probe(struct spi_device *spi) |
@@ -274,6 +299,7 @@ static int __devexit wl1251_spi_remove(struct spi_device *spi) | |||
274 | { | 299 | { |
275 | struct wl1251 *wl = dev_get_drvdata(&spi->dev); | 300 | struct wl1251 *wl = dev_get_drvdata(&spi->dev); |
276 | 301 | ||
302 | free_irq(wl->irq, wl); | ||
277 | wl1251_free_hw(wl); | 303 | wl1251_free_hw(wl); |
278 | 304 | ||
279 | return 0; | 305 | return 0; |