diff options
author | Alex Dubov <oakad@yahoo.com> | 2007-04-12 02:59:15 -0400 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2007-05-01 07:04:13 -0400 |
commit | 3540af8ffddcdbc7573451ac0b5cd57a2eaf8af5 (patch) | |
tree | 387b17747358710e15e06dc48884b9f333fc1729 /drivers/misc/tifm_7xx1.c | |
parent | e23f2b8a1a52c00f0150659eb0bfde3a73976ffe (diff) |
tifm: replace per-adapter kthread with freezeable workqueue
Freezeable workqueue makes sure that adapter work items (device insertions
and removals) would be handled after the system is fully resumed. Previously
this was achieved by explicit freezing of the kthread.
Signed-off-by: Alex Dubov <oakad@yahoo.com>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/misc/tifm_7xx1.c')
-rw-r--r-- | drivers/misc/tifm_7xx1.c | 89 |
1 files changed, 34 insertions, 55 deletions
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index fd7b8dadc821..e5655fef42d7 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c | |||
@@ -28,7 +28,7 @@ static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) | |||
28 | 28 | ||
29 | spin_lock_irqsave(&fm->lock, flags); | 29 | spin_lock_irqsave(&fm->lock, flags); |
30 | fm->socket_change_set |= 1 << sock->socket_id; | 30 | fm->socket_change_set |= 1 << sock->socket_id; |
31 | wake_up_all(&fm->change_set_notify); | 31 | tifm_queue_work(&fm->media_switcher); |
32 | spin_unlock_irqrestore(&fm->lock, flags); | 32 | spin_unlock_irqrestore(&fm->lock, flags); |
33 | } | 33 | } |
34 | 34 | ||
@@ -64,10 +64,12 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) | |||
64 | } | 64 | } |
65 | writel(irq_status, fm->addr + FM_INTERRUPT_STATUS); | 65 | writel(irq_status, fm->addr + FM_INTERRUPT_STATUS); |
66 | 66 | ||
67 | if (!fm->socket_change_set) | 67 | if (fm->finish_me) |
68 | complete_all(fm->finish_me); | ||
69 | else if (!fm->socket_change_set) | ||
68 | writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); | 70 | writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); |
69 | else | 71 | else |
70 | wake_up_all(&fm->change_set_notify); | 72 | tifm_queue_work(&fm->media_switcher); |
71 | 73 | ||
72 | spin_unlock(&fm->lock); | 74 | spin_unlock(&fm->lock); |
73 | return IRQ_HANDLED; | 75 | return IRQ_HANDLED; |
@@ -125,37 +127,29 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num) | |||
125 | return base_addr + ((sock_num + 1) << 10); | 127 | return base_addr + ((sock_num + 1) << 10); |
126 | } | 128 | } |
127 | 129 | ||
128 | static int tifm_7xx1_switch_media(void *data) | 130 | static void tifm_7xx1_switch_media(struct work_struct *work) |
129 | { | 131 | { |
130 | struct tifm_adapter *fm = data; | 132 | struct tifm_adapter *fm = container_of(work, struct tifm_adapter, |
133 | media_switcher); | ||
131 | unsigned long flags; | 134 | unsigned long flags; |
132 | unsigned char media_id; | 135 | unsigned char media_id; |
133 | char *card_name = "xx"; | 136 | char *card_name = "xx"; |
134 | int cnt, rc; | 137 | int cnt; |
135 | struct tifm_dev *sock; | 138 | struct tifm_dev *sock; |
136 | unsigned int socket_change_set; | 139 | unsigned int socket_change_set; |
137 | 140 | ||
138 | while (1) { | 141 | spin_lock_irqsave(&fm->lock, flags); |
139 | rc = wait_event_interruptible(fm->change_set_notify, | 142 | socket_change_set = fm->socket_change_set; |
140 | fm->socket_change_set); | 143 | fm->socket_change_set = 0; |
141 | if (rc == -ERESTARTSYS) | ||
142 | try_to_freeze(); | ||
143 | |||
144 | spin_lock_irqsave(&fm->lock, flags); | ||
145 | socket_change_set = fm->socket_change_set; | ||
146 | fm->socket_change_set = 0; | ||
147 | 144 | ||
148 | dev_dbg(fm->dev, "checking media set %x\n", | 145 | dev_dbg(fm->dev, "checking media set %x\n", |
149 | socket_change_set); | 146 | socket_change_set); |
150 | 147 | ||
151 | if (kthread_should_stop()) | 148 | if (!socket_change_set) { |
152 | socket_change_set = (1 << fm->num_sockets) - 1; | ||
153 | spin_unlock_irqrestore(&fm->lock, flags); | 149 | spin_unlock_irqrestore(&fm->lock, flags); |
150 | return; | ||
151 | } | ||
154 | 152 | ||
155 | if (!socket_change_set) | ||
156 | continue; | ||
157 | |||
158 | spin_lock_irqsave(&fm->lock, flags); | ||
159 | for (cnt = 0; cnt < fm->num_sockets; cnt++) { | 153 | for (cnt = 0; cnt < fm->num_sockets; cnt++) { |
160 | if (!(socket_change_set & (1 << cnt))) | 154 | if (!(socket_change_set & (1 << cnt))) |
161 | continue; | 155 | continue; |
@@ -172,8 +166,6 @@ static int tifm_7xx1_switch_media(void *data) | |||
172 | tifm_7xx1_sock_addr(fm->addr, cnt) | 166 | tifm_7xx1_sock_addr(fm->addr, cnt) |
173 | + SOCK_CONTROL); | 167 | + SOCK_CONTROL); |
174 | } | 168 | } |
175 | if (kthread_should_stop()) | ||
176 | continue; | ||
177 | 169 | ||
178 | spin_unlock_irqrestore(&fm->lock, flags); | 170 | spin_unlock_irqrestore(&fm->lock, flags); |
179 | media_id = tifm_7xx1_toggle_sock_power( | 171 | media_id = tifm_7xx1_toggle_sock_power( |
@@ -222,30 +214,16 @@ static int tifm_7xx1_switch_media(void *data) | |||
222 | } | 214 | } |
223 | } | 215 | } |
224 | 216 | ||
225 | if (!kthread_should_stop()) { | 217 | writel(TIFM_IRQ_FIFOMASK(socket_change_set) |
226 | writel(TIFM_IRQ_FIFOMASK(socket_change_set) | 218 | | TIFM_IRQ_CARDMASK(socket_change_set), |
227 | | TIFM_IRQ_CARDMASK(socket_change_set), | 219 | fm->addr + FM_CLEAR_INTERRUPT_ENABLE); |
228 | fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | 220 | |
229 | writel(TIFM_IRQ_FIFOMASK(socket_change_set) | 221 | writel(TIFM_IRQ_FIFOMASK(socket_change_set) |
230 | | TIFM_IRQ_CARDMASK(socket_change_set), | 222 | | TIFM_IRQ_CARDMASK(socket_change_set), |
231 | fm->addr + FM_SET_INTERRUPT_ENABLE); | 223 | fm->addr + FM_SET_INTERRUPT_ENABLE); |
232 | writel(TIFM_IRQ_ENABLE, | 224 | |
233 | fm->addr + FM_SET_INTERRUPT_ENABLE); | 225 | writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); |
234 | spin_unlock_irqrestore(&fm->lock, flags); | 226 | spin_unlock_irqrestore(&fm->lock, flags); |
235 | } else { | ||
236 | for (cnt = 0; cnt < fm->num_sockets; cnt++) { | ||
237 | if (fm->sockets[cnt]) | ||
238 | fm->socket_change_set |= 1 << cnt; | ||
239 | } | ||
240 | if (!fm->socket_change_set) { | ||
241 | spin_unlock_irqrestore(&fm->lock, flags); | ||
242 | return 0; | ||
243 | } else { | ||
244 | spin_unlock_irqrestore(&fm->lock, flags); | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | return 0; | ||
249 | } | 227 | } |
250 | 228 | ||
251 | #ifdef CONFIG_PM | 229 | #ifdef CONFIG_PM |
@@ -267,6 +245,7 @@ static int tifm_7xx1_resume(struct pci_dev *dev) | |||
267 | int cnt, rc; | 245 | int cnt, rc; |
268 | unsigned long flags; | 246 | unsigned long flags; |
269 | unsigned char new_ids[fm->num_sockets]; | 247 | unsigned char new_ids[fm->num_sockets]; |
248 | DECLARE_COMPLETION_ONSTACK(finish_resume); | ||
270 | 249 | ||
271 | pci_set_power_state(dev, PCI_D0); | 250 | pci_set_power_state(dev, PCI_D0); |
272 | pci_restore_state(dev); | 251 | pci_restore_state(dev); |
@@ -299,12 +278,14 @@ static int tifm_7xx1_resume(struct pci_dev *dev) | |||
299 | return 0; | 278 | return 0; |
300 | } else { | 279 | } else { |
301 | fm->socket_change_set = 0; | 280 | fm->socket_change_set = 0; |
281 | fm->finish_me = &finish_resume; | ||
302 | spin_unlock_irqrestore(&fm->lock, flags); | 282 | spin_unlock_irqrestore(&fm->lock, flags); |
303 | } | 283 | } |
304 | 284 | ||
305 | wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ); | 285 | wait_for_completion_timeout(&finish_resume, HZ); |
306 | 286 | ||
307 | spin_lock_irqsave(&fm->lock, flags); | 287 | spin_lock_irqsave(&fm->lock, flags); |
288 | fm->finish_me = NULL; | ||
308 | writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set) | 289 | writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set) |
309 | | TIFM_IRQ_CARDMASK(fm->socket_change_set), | 290 | | TIFM_IRQ_CARDMASK(fm->socket_change_set), |
310 | fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | 291 | fm->addr + FM_CLEAR_INTERRUPT_ENABLE); |
@@ -365,6 +346,7 @@ static int tifm_7xx1_probe(struct pci_dev *dev, | |||
365 | if (!fm->sockets) | 346 | if (!fm->sockets) |
366 | goto err_out_free; | 347 | goto err_out_free; |
367 | 348 | ||
349 | INIT_WORK(&fm->media_switcher, tifm_7xx1_switch_media); | ||
368 | fm->eject = tifm_7xx1_eject; | 350 | fm->eject = tifm_7xx1_eject; |
369 | pci_set_drvdata(dev, fm); | 351 | pci_set_drvdata(dev, fm); |
370 | 352 | ||
@@ -377,15 +359,14 @@ static int tifm_7xx1_probe(struct pci_dev *dev, | |||
377 | if (rc) | 359 | if (rc) |
378 | goto err_out_unmap; | 360 | goto err_out_unmap; |
379 | 361 | ||
380 | init_waitqueue_head(&fm->change_set_notify); | 362 | rc = tifm_add_adapter(fm); |
381 | rc = tifm_add_adapter(fm, tifm_7xx1_switch_media); | ||
382 | if (rc) | 363 | if (rc) |
383 | goto err_out_irq; | 364 | goto err_out_irq; |
384 | 365 | ||
385 | writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | 366 | writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); |
386 | writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), | 367 | writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), |
387 | fm->addr + FM_SET_INTERRUPT_ENABLE); | 368 | fm->addr + FM_SET_INTERRUPT_ENABLE); |
388 | wake_up_process(fm->media_switcher); | 369 | |
389 | return 0; | 370 | return 0; |
390 | 371 | ||
391 | err_out_irq: | 372 | err_out_irq: |
@@ -417,8 +398,6 @@ static void tifm_7xx1_remove(struct pci_dev *dev) | |||
417 | fm->socket_change_set = (1 << fm->num_sockets) - 1; | 398 | fm->socket_change_set = (1 << fm->num_sockets) - 1; |
418 | spin_unlock_irqrestore(&fm->lock, flags); | 399 | spin_unlock_irqrestore(&fm->lock, flags); |
419 | 400 | ||
420 | kthread_stop(fm->media_switcher); | ||
421 | |||
422 | tifm_remove_adapter(fm); | 401 | tifm_remove_adapter(fm); |
423 | 402 | ||
424 | pci_set_drvdata(dev, NULL); | 403 | pci_set_drvdata(dev, NULL); |