aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/tifm_7xx1.c
diff options
context:
space:
mode:
authorAlex Dubov <oakad@yahoo.com>2007-04-12 02:59:15 -0400
committerPierre Ossman <drzeus@drzeus.cx>2007-05-01 07:04:13 -0400
commit3540af8ffddcdbc7573451ac0b5cd57a2eaf8af5 (patch)
tree387b17747358710e15e06dc48884b9f333fc1729 /drivers/misc/tifm_7xx1.c
parente23f2b8a1a52c00f0150659eb0bfde3a73976ffe (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.c89
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
128static int tifm_7xx1_switch_media(void *data) 130static 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
391err_out_irq: 372err_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);