diff options
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); |