diff options
-rw-r--r-- | drivers/misc/tifm_7xx1.c | 89 | ||||
-rw-r--r-- | drivers/misc/tifm_core.c | 51 | ||||
-rw-r--r-- | include/linux/tifm.h | 8 |
3 files changed, 72 insertions, 76 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); |
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 | ||
19 | static struct workqueue_struct *workqueue; | ||
19 | static DEFINE_IDR(tifm_adapter_idr); | 20 | static DEFINE_IDR(tifm_adapter_idr); |
20 | static DEFINE_SPINLOCK(tifm_adapter_lock); | 21 | static DEFINE_SPINLOCK(tifm_adapter_lock); |
21 | 22 | ||
@@ -184,8 +185,7 @@ void tifm_free_adapter(struct tifm_adapter *fm) | |||
184 | } | 185 | } |
185 | EXPORT_SYMBOL(tifm_free_adapter); | 186 | EXPORT_SYMBOL(tifm_free_adapter); |
186 | 187 | ||
187 | int tifm_add_adapter(struct tifm_adapter *fm, | 188 | int 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 | ||
215 | void tifm_remove_adapter(struct tifm_adapter *fm) | 212 | void 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 | } |
268 | EXPORT_SYMBOL(tifm_unmap_sg); | 266 | EXPORT_SYMBOL(tifm_unmap_sg); |
269 | 267 | ||
268 | void tifm_queue_work(struct work_struct *work) | ||
269 | { | ||
270 | queue_work(workqueue, work); | ||
271 | } | ||
272 | EXPORT_SYMBOL(tifm_queue_work); | ||
273 | |||
270 | int tifm_register_driver(struct tifm_driver *drv) | 274 | int 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 | ||
284 | static int __init tifm_init(void) | 288 | static 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 | |||
307 | err_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 | ||
303 | subsys_initcall(tifm_init); | 320 | subsys_initcall(tifm_init); |
diff --git a/include/linux/tifm.h b/include/linux/tifm.h index 57b2653494cf..d9de79275c21 100644 --- a/include/linux/tifm.h +++ b/include/linux/tifm.h | |||
@@ -111,11 +111,11 @@ struct tifm_adapter { | |||
111 | spinlock_t lock; | 111 | spinlock_t lock; |
112 | unsigned int irq_status; | 112 | unsigned int irq_status; |
113 | unsigned int socket_change_set; | 113 | unsigned int socket_change_set; |
114 | wait_queue_head_t change_set_notify; | ||
115 | unsigned int id; | 114 | unsigned int id; |
116 | unsigned int num_sockets; | 115 | unsigned int num_sockets; |
116 | struct completion *finish_me; | ||
117 | struct tifm_dev **sockets; | 117 | struct tifm_dev **sockets; |
118 | struct task_struct *media_switcher; | 118 | struct work_struct media_switcher; |
119 | struct class_device cdev; | 119 | struct class_device cdev; |
120 | struct device *dev; | 120 | struct device *dev; |
121 | 121 | ||
@@ -125,7 +125,7 @@ struct tifm_adapter { | |||
125 | struct tifm_adapter *tifm_alloc_adapter(void); | 125 | struct tifm_adapter *tifm_alloc_adapter(void); |
126 | void tifm_free_device(struct device *dev); | 126 | void tifm_free_device(struct device *dev); |
127 | void tifm_free_adapter(struct tifm_adapter *fm); | 127 | void tifm_free_adapter(struct tifm_adapter *fm); |
128 | int tifm_add_adapter(struct tifm_adapter *fm, int (*mediathreadfn)(void *data)); | 128 | int tifm_add_adapter(struct tifm_adapter *fm); |
129 | void tifm_remove_adapter(struct tifm_adapter *fm); | 129 | void tifm_remove_adapter(struct tifm_adapter *fm); |
130 | struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm); | 130 | struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm); |
131 | int tifm_register_driver(struct tifm_driver *drv); | 131 | int tifm_register_driver(struct tifm_driver *drv); |
@@ -135,7 +135,7 @@ int tifm_map_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents, | |||
135 | int direction); | 135 | int direction); |
136 | void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents, | 136 | void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents, |
137 | int direction); | 137 | int direction); |
138 | 138 | void tifm_queue_work(struct work_struct *work); | |
139 | 139 | ||
140 | static inline void *tifm_get_drvdata(struct tifm_dev *dev) | 140 | static inline void *tifm_get_drvdata(struct tifm_dev *dev) |
141 | { | 141 | { |