aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
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
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')
-rw-r--r--drivers/misc/tifm_7xx1.c89
-rw-r--r--drivers/misc/tifm_core.c51
2 files changed, 68 insertions, 72 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);
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index 6b2c447dc8ee..ef8a97b819dd 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -16,6 +16,7 @@
16#define DRIVER_NAME "tifm_core" 16#define DRIVER_NAME "tifm_core"
17#define DRIVER_VERSION "0.8" 17#define DRIVER_VERSION "0.8"
18 18
19static struct workqueue_struct *workqueue;
19static DEFINE_IDR(tifm_adapter_idr); 20static DEFINE_IDR(tifm_adapter_idr);
20static DEFINE_SPINLOCK(tifm_adapter_lock); 21static DEFINE_SPINLOCK(tifm_adapter_lock);
21 22
@@ -184,8 +185,7 @@ void tifm_free_adapter(struct tifm_adapter *fm)
184} 185}
185EXPORT_SYMBOL(tifm_free_adapter); 186EXPORT_SYMBOL(tifm_free_adapter);
186 187
187int tifm_add_adapter(struct tifm_adapter *fm, 188int tifm_add_adapter(struct tifm_adapter *fm)
188 int (*mediathreadfn)(void *data))
189{ 189{
190 int rc; 190 int rc;
191 191
@@ -197,16 +197,13 @@ int tifm_add_adapter(struct tifm_adapter *fm,
197 spin_unlock(&tifm_adapter_lock); 197 spin_unlock(&tifm_adapter_lock);
198 if (!rc) { 198 if (!rc) {
199 snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id); 199 snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
200 fm->media_switcher = kthread_create(mediathreadfn, 200 rc = class_device_add(&fm->cdev);
201 fm, "tifm/%u", fm->id);
202 201
203 if (!IS_ERR(fm->media_switcher)) 202 if (rc) {
204 return class_device_add(&fm->cdev); 203 spin_lock(&tifm_adapter_lock);
205 204 idr_remove(&tifm_adapter_idr, fm->id);
206 spin_lock(&tifm_adapter_lock); 205 spin_unlock(&tifm_adapter_lock);
207 idr_remove(&tifm_adapter_idr, fm->id); 206 }
208 spin_unlock(&tifm_adapter_lock);
209 rc = -ENOMEM;
210 } 207 }
211 return rc; 208 return rc;
212} 209}
@@ -214,6 +211,7 @@ EXPORT_SYMBOL(tifm_add_adapter);
214 211
215void tifm_remove_adapter(struct tifm_adapter *fm) 212void tifm_remove_adapter(struct tifm_adapter *fm)
216{ 213{
214 flush_workqueue(workqueue);
217 class_device_del(&fm->cdev); 215 class_device_del(&fm->cdev);
218 216
219 spin_lock(&tifm_adapter_lock); 217 spin_lock(&tifm_adapter_lock);
@@ -267,6 +265,12 @@ void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
267} 265}
268EXPORT_SYMBOL(tifm_unmap_sg); 266EXPORT_SYMBOL(tifm_unmap_sg);
269 267
268void tifm_queue_work(struct work_struct *work)
269{
270 queue_work(workqueue, work);
271}
272EXPORT_SYMBOL(tifm_queue_work);
273
270int tifm_register_driver(struct tifm_driver *drv) 274int tifm_register_driver(struct tifm_driver *drv)
271{ 275{
272 drv->driver.bus = &tifm_bus_type; 276 drv->driver.bus = &tifm_bus_type;
@@ -283,13 +287,25 @@ EXPORT_SYMBOL(tifm_unregister_driver);
283 287
284static int __init tifm_init(void) 288static int __init tifm_init(void)
285{ 289{
286 int rc = bus_register(&tifm_bus_type); 290 int rc;
287 291
288 if (!rc) { 292 workqueue = create_freezeable_workqueue("tifm");
289 rc = class_register(&tifm_adapter_class); 293 if (!workqueue)
290 if (rc) 294 return -ENOMEM;
291 bus_unregister(&tifm_bus_type); 295
292 } 296 rc = bus_register(&tifm_bus_type);
297
298 if (rc)
299 goto err_out_wq;
300
301 rc = class_register(&tifm_adapter_class);
302 if (!rc)
303 return 0;
304
305 bus_unregister(&tifm_bus_type);
306
307err_out_wq:
308 destroy_workqueue(workqueue);
293 309
294 return rc; 310 return rc;
295} 311}
@@ -298,6 +314,7 @@ static void __exit tifm_exit(void)
298{ 314{
299 class_unregister(&tifm_adapter_class); 315 class_unregister(&tifm_adapter_class);
300 bus_unregister(&tifm_bus_type); 316 bus_unregister(&tifm_bus_type);
317 destroy_workqueue(workqueue);
301} 318}
302 319
303subsys_initcall(tifm_init); 320subsys_initcall(tifm_init);