aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/misc/tifm_7xx1.c151
-rw-r--r--drivers/misc/tifm_core.c11
-rw-r--r--include/linux/tifm.h10
3 files changed, 98 insertions, 74 deletions
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
index 5ab81dd37857..d3e8ff46c237 100644
--- a/drivers/misc/tifm_7xx1.c
+++ b/drivers/misc/tifm_7xx1.c
@@ -11,6 +11,7 @@
11 11
12#include <linux/tifm.h> 12#include <linux/tifm.h>
13#include <linux/dma-mapping.h> 13#include <linux/dma-mapping.h>
14#include <linux/freezer.h>
14 15
15#define DRIVER_NAME "tifm_7xx1" 16#define DRIVER_NAME "tifm_7xx1"
16#define DRIVER_VERSION "0.7" 17#define DRIVER_VERSION "0.7"
@@ -20,10 +21,8 @@ static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
20 unsigned long flags; 21 unsigned long flags;
21 22
22 spin_lock_irqsave(&fm->lock, flags); 23 spin_lock_irqsave(&fm->lock, flags);
23 if (!fm->inhibit_new_cards) { 24 fm->socket_change_set |= 1 << sock->socket_id;
24 fm->socket_change_set |= 1 << sock->socket_id; 25 wake_up_all(&fm->change_set_notify);
25 queue_work(fm->wq, &fm->media_switcher);
26 }
27 spin_unlock_irqrestore(&fm->lock, flags); 26 spin_unlock_irqrestore(&fm->lock, flags);
28} 27}
29 28
@@ -59,14 +58,10 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
59 } 58 }
60 writel(irq_status, fm->addr + FM_INTERRUPT_STATUS); 59 writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);
61 60
62 if (!fm->inhibit_new_cards) { 61 if (!fm->socket_change_set)
63 if (!fm->socket_change_set) { 62 writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
64 writel(TIFM_IRQ_ENABLE, 63 else
65 fm->addr + FM_SET_INTERRUPT_ENABLE); 64 wake_up_all(&fm->change_set_notify);
66 } else {
67 queue_work(fm->wq, &fm->media_switcher);
68 }
69 }
70 65
71 spin_unlock(&fm->lock); 66 spin_unlock(&fm->lock);
72 return IRQ_HANDLED; 67 return IRQ_HANDLED;
@@ -123,21 +118,22 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)
123 return base_addr + ((sock_num + 1) << 10); 118 return base_addr + ((sock_num + 1) << 10);
124} 119}
125 120
126static void tifm_7xx1_switch_media(struct work_struct *work) 121static int tifm_7xx1_switch_media(void *data)
127{ 122{
128 struct tifm_adapter *fm = 123 struct tifm_adapter *fm = data;
129 container_of(work, struct tifm_adapter, media_switcher);
130 unsigned long flags; 124 unsigned long flags;
131 tifm_media_id media_id; 125 tifm_media_id media_id;
132 char *card_name = "xx"; 126 char *card_name = "xx";
133 int cnt; 127 int cnt, rc;
134 struct tifm_dev *sock; 128 struct tifm_dev *sock;
135 unsigned int socket_change_set; 129 unsigned int socket_change_set;
136 130
137 if (!class_device_get(&fm->cdev))
138 return;
139
140 while (1) { 131 while (1) {
132 rc = wait_event_interruptible(fm->change_set_notify,
133 fm->socket_change_set);
134 if (rc == -ERESTARTSYS)
135 try_to_freeze();
136
141 spin_lock_irqsave(&fm->lock, flags); 137 spin_lock_irqsave(&fm->lock, flags);
142 socket_change_set = fm->socket_change_set; 138 socket_change_set = fm->socket_change_set;
143 fm->socket_change_set = 0; 139 fm->socket_change_set = 0;
@@ -145,12 +141,12 @@ static void tifm_7xx1_switch_media(struct work_struct *work)
145 dev_dbg(fm->dev, "checking media set %x\n", 141 dev_dbg(fm->dev, "checking media set %x\n",
146 socket_change_set); 142 socket_change_set);
147 143
148 if (fm->inhibit_new_cards) 144 if (kthread_should_stop())
149 socket_change_set = (1 << fm->num_sockets) - 1; 145 socket_change_set = (1 << fm->num_sockets) - 1;
150 spin_unlock_irqrestore(&fm->lock, flags); 146 spin_unlock_irqrestore(&fm->lock, flags);
151 147
152 if (!socket_change_set) 148 if (!socket_change_set)
153 break; 149 continue;
154 150
155 spin_lock_irqsave(&fm->lock, flags); 151 spin_lock_irqsave(&fm->lock, flags);
156 for (cnt = 0; cnt < fm->num_sockets; cnt++) { 152 for (cnt = 0; cnt < fm->num_sockets; cnt++) {
@@ -169,7 +165,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work)
169 tifm_7xx1_sock_addr(fm->addr, cnt) 165 tifm_7xx1_sock_addr(fm->addr, cnt)
170 + SOCK_CONTROL); 166 + SOCK_CONTROL);
171 } 167 }
172 if (fm->inhibit_new_cards) 168 if (kthread_should_stop())
173 continue; 169 continue;
174 170
175 spin_unlock_irqrestore(&fm->lock, flags); 171 spin_unlock_irqrestore(&fm->lock, flags);
@@ -218,7 +214,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work)
218 } 214 }
219 } 215 }
220 216
221 if (!fm->inhibit_new_cards) { 217 if (!kthread_should_stop()) {
222 writel(TIFM_IRQ_FIFOMASK(socket_change_set) 218 writel(TIFM_IRQ_FIFOMASK(socket_change_set)
223 | TIFM_IRQ_CARDMASK(socket_change_set), 219 | TIFM_IRQ_CARDMASK(socket_change_set),
224 fm->addr + FM_CLEAR_INTERRUPT_ENABLE); 220 fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
@@ -228,7 +224,6 @@ static void tifm_7xx1_switch_media(struct work_struct *work)
228 writel(TIFM_IRQ_ENABLE, 224 writel(TIFM_IRQ_ENABLE,
229 fm->addr + FM_SET_INTERRUPT_ENABLE); 225 fm->addr + FM_SET_INTERRUPT_ENABLE);
230 spin_unlock_irqrestore(&fm->lock, flags); 226 spin_unlock_irqrestore(&fm->lock, flags);
231 break;
232 } else { 227 } else {
233 for (cnt = 0; cnt < fm->num_sockets; cnt++) { 228 for (cnt = 0; cnt < fm->num_sockets; cnt++) {
234 if (fm->sockets[cnt]) 229 if (fm->sockets[cnt])
@@ -236,56 +231,93 @@ static void tifm_7xx1_switch_media(struct work_struct *work)
236 } 231 }
237 if (!fm->socket_change_set) { 232 if (!fm->socket_change_set) {
238 spin_unlock_irqrestore(&fm->lock, flags); 233 spin_unlock_irqrestore(&fm->lock, flags);
239 break; 234 return 0;
240 } else { 235 } else {
241 spin_unlock_irqrestore(&fm->lock, flags); 236 spin_unlock_irqrestore(&fm->lock, flags);
242 } 237 }
243 } 238 }
244 } 239 }
245 class_device_put(&fm->cdev); 240 return 0;
246} 241}
247 242
243#ifdef CONFIG_PM
244
248static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state) 245static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
249{ 246{
250 struct tifm_adapter *fm = pci_get_drvdata(dev); 247 dev_dbg(&dev->dev, "suspending host\n");
251 unsigned long flags;
252 248
253 spin_lock_irqsave(&fm->lock, flags); 249 pci_save_state(dev);
254 fm->inhibit_new_cards = 1; 250 pci_enable_wake(dev, pci_choose_state(dev, state), 0);
255 fm->socket_change_set = 0xf; 251 pci_disable_device(dev);
256 writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); 252 pci_set_power_state(dev, pci_choose_state(dev, state));
257 spin_unlock_irqrestore(&fm->lock, flags);
258 flush_workqueue(fm->wq);
259
260 tifm_7xx1_switch_media(&fm->media_switcher);
261
262 pci_set_power_state(dev, PCI_D3hot);
263 pci_disable_device(dev);
264 pci_save_state(dev);
265 return 0; 253 return 0;
266} 254}
267 255
268static int tifm_7xx1_resume(struct pci_dev *dev) 256static int tifm_7xx1_resume(struct pci_dev *dev)
269{ 257{
270 struct tifm_adapter *fm = pci_get_drvdata(dev); 258 struct tifm_adapter *fm = pci_get_drvdata(dev);
259 int cnt, rc;
271 unsigned long flags; 260 unsigned long flags;
261 tifm_media_id new_ids[fm->num_sockets];
272 262
263 pci_set_power_state(dev, PCI_D0);
273 pci_restore_state(dev); 264 pci_restore_state(dev);
274 pci_enable_device(dev); 265 rc = pci_enable_device(dev);
275 pci_set_power_state(dev, PCI_D0); 266 if (rc)
276 pci_set_master(dev); 267 return rc;
268 pci_set_master(dev);
269
270 dev_dbg(&dev->dev, "resuming host\n");
277 271
272 for (cnt = 0; cnt < fm->num_sockets; cnt++)
273 new_ids[cnt] = tifm_7xx1_toggle_sock_power(
274 tifm_7xx1_sock_addr(fm->addr, cnt),
275 fm->num_sockets == 2);
278 spin_lock_irqsave(&fm->lock, flags); 276 spin_lock_irqsave(&fm->lock, flags);
279 fm->inhibit_new_cards = 0; 277 fm->socket_change_set = 0;
280 writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS); 278 for (cnt = 0; cnt < fm->num_sockets; cnt++) {
281 writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); 279 if (fm->sockets[cnt]) {
280 if (fm->sockets[cnt]->media_id == new_ids[cnt])
281 fm->socket_change_set |= 1 << cnt;
282
283 fm->sockets[cnt]->media_id = new_ids[cnt];
284 }
285 }
286
282 writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), 287 writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
283 fm->addr + FM_SET_INTERRUPT_ENABLE); 288 fm->addr + FM_SET_INTERRUPT_ENABLE);
284 fm->socket_change_set = 0xf; 289 if (!fm->socket_change_set) {
290 spin_unlock_irqrestore(&fm->lock, flags);
291 return 0;
292 } else {
293 fm->socket_change_set = 0;
294 spin_unlock_irqrestore(&fm->lock, flags);
295 }
296
297 wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ);
298
299 spin_lock_irqsave(&fm->lock, flags);
300 writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
301 | TIFM_IRQ_CARDMASK(fm->socket_change_set),
302 fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
303 writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
304 | TIFM_IRQ_CARDMASK(fm->socket_change_set),
305 fm->addr + FM_SET_INTERRUPT_ENABLE);
306 writel(TIFM_IRQ_ENABLE,
307 fm->addr + FM_SET_INTERRUPT_ENABLE);
308 fm->socket_change_set = 0;
309
285 spin_unlock_irqrestore(&fm->lock, flags); 310 spin_unlock_irqrestore(&fm->lock, flags);
286 return 0; 311 return 0;
287} 312}
288 313
314#else
315
316#define tifm_7xx1_suspend NULL
317#define tifm_7xx1_resume NULL
318
319#endif /* CONFIG_PM */
320
289static int tifm_7xx1_probe(struct pci_dev *dev, 321static int tifm_7xx1_probe(struct pci_dev *dev,
290 const struct pci_device_id *dev_id) 322 const struct pci_device_id *dev_id)
291{ 323{
@@ -324,7 +356,6 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
324 if (!fm->sockets) 356 if (!fm->sockets)
325 goto err_out_free; 357 goto err_out_free;
326 358
327 INIT_WORK(&fm->media_switcher, tifm_7xx1_switch_media);
328 fm->eject = tifm_7xx1_eject; 359 fm->eject = tifm_7xx1_eject;
329 pci_set_drvdata(dev, fm); 360 pci_set_drvdata(dev, fm);
330 361
@@ -337,16 +368,15 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
337 if (rc) 368 if (rc)
338 goto err_out_unmap; 369 goto err_out_unmap;
339 370
340 rc = tifm_add_adapter(fm); 371 init_waitqueue_head(&fm->change_set_notify);
372 rc = tifm_add_adapter(fm, tifm_7xx1_switch_media);
341 if (rc) 373 if (rc)
342 goto err_out_irq; 374 goto err_out_irq;
343 375
344 writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); 376 writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
345 writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), 377 writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
346 fm->addr + FM_SET_INTERRUPT_ENABLE); 378 fm->addr + FM_SET_INTERRUPT_ENABLE);
347 379 wake_up_process(fm->media_switcher);
348 fm->socket_change_set = 0xf;
349
350 return 0; 380 return 0;
351 381
352err_out_irq: 382err_out_irq:
@@ -370,18 +400,15 @@ static void tifm_7xx1_remove(struct pci_dev *dev)
370 struct tifm_adapter *fm = pci_get_drvdata(dev); 400 struct tifm_adapter *fm = pci_get_drvdata(dev);
371 unsigned long flags; 401 unsigned long flags;
372 402
403 writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
404 mmiowb();
405 free_irq(dev->irq, fm);
406
373 spin_lock_irqsave(&fm->lock, flags); 407 spin_lock_irqsave(&fm->lock, flags);
374 fm->inhibit_new_cards = 1; 408 fm->socket_change_set = (1 << fm->num_sockets) - 1;
375 fm->socket_change_set = 0xf;
376 writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
377 spin_unlock_irqrestore(&fm->lock, flags); 409 spin_unlock_irqrestore(&fm->lock, flags);
378 410
379 flush_workqueue(fm->wq); 411 kthread_stop(fm->media_switcher);
380
381 tifm_7xx1_switch_media(&fm->media_switcher);
382
383 writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
384 free_irq(dev->irq, fm);
385 412
386 tifm_remove_adapter(fm); 413 tifm_remove_adapter(fm);
387 414
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index 3eaf2c985b7d..4d62dab2ada3 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -71,8 +71,6 @@ static void tifm_free(struct class_device *cdev)
71 struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev); 71 struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
72 72
73 kfree(fm->sockets); 73 kfree(fm->sockets);
74 if (fm->wq)
75 destroy_workqueue(fm->wq);
76 kfree(fm); 74 kfree(fm);
77} 75}
78 76
@@ -101,7 +99,8 @@ void tifm_free_adapter(struct tifm_adapter *fm)
101} 99}
102EXPORT_SYMBOL(tifm_free_adapter); 100EXPORT_SYMBOL(tifm_free_adapter);
103 101
104int tifm_add_adapter(struct tifm_adapter *fm) 102int tifm_add_adapter(struct tifm_adapter *fm,
103 int (*mediathreadfn)(void *data))
105{ 104{
106 int rc; 105 int rc;
107 106
@@ -113,10 +112,10 @@ int tifm_add_adapter(struct tifm_adapter *fm)
113 spin_unlock(&tifm_adapter_lock); 112 spin_unlock(&tifm_adapter_lock);
114 if (!rc) { 113 if (!rc) {
115 snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id); 114 snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
116 strncpy(fm->wq_name, fm->cdev.class_id, KOBJ_NAME_LEN); 115 fm->media_switcher = kthread_create(mediathreadfn,
116 fm, "tifm/%u", fm->id);
117 117
118 fm->wq = create_singlethread_workqueue(fm->wq_name); 118 if (!IS_ERR(fm->media_switcher))
119 if (fm->wq)
120 return class_device_add(&fm->cdev); 119 return class_device_add(&fm->cdev);
121 120
122 spin_lock(&tifm_adapter_lock); 121 spin_lock(&tifm_adapter_lock);
diff --git a/include/linux/tifm.h b/include/linux/tifm.h
index eaf9e1f48780..e5a8295f9fbc 100644
--- a/include/linux/tifm.h
+++ b/include/linux/tifm.h
@@ -17,7 +17,7 @@
17#include <linux/wait.h> 17#include <linux/wait.h>
18#include <linux/delay.h> 18#include <linux/delay.h>
19#include <linux/pci.h> 19#include <linux/pci.h>
20#include <linux/scatterlist.h> 20#include <linux/kthread.h>
21 21
22/* Host registers (relative to pci base address): */ 22/* Host registers (relative to pci base address): */
23enum { 23enum {
@@ -110,13 +110,11 @@ struct tifm_adapter {
110 spinlock_t lock; 110 spinlock_t lock;
111 unsigned int irq_status; 111 unsigned int irq_status;
112 unsigned int socket_change_set; 112 unsigned int socket_change_set;
113 wait_queue_head_t change_set_notify;
113 unsigned int id; 114 unsigned int id;
114 unsigned int num_sockets; 115 unsigned int num_sockets;
115 struct tifm_dev **sockets; 116 struct tifm_dev **sockets;
116 char wq_name[KOBJ_NAME_LEN]; 117 struct task_struct *media_switcher;
117 unsigned int inhibit_new_cards;
118 struct workqueue_struct *wq;
119 struct work_struct media_switcher;
120 struct class_device cdev; 118 struct class_device cdev;
121 struct device *dev; 119 struct device *dev;
122 120
@@ -126,7 +124,7 @@ struct tifm_adapter {
126struct tifm_adapter *tifm_alloc_adapter(void); 124struct tifm_adapter *tifm_alloc_adapter(void);
127void tifm_free_device(struct device *dev); 125void tifm_free_device(struct device *dev);
128void tifm_free_adapter(struct tifm_adapter *fm); 126void tifm_free_adapter(struct tifm_adapter *fm);
129int tifm_add_adapter(struct tifm_adapter *fm); 127int tifm_add_adapter(struct tifm_adapter *fm, int (*mediathreadfn)(void *data));
130void tifm_remove_adapter(struct tifm_adapter *fm); 128void tifm_remove_adapter(struct tifm_adapter *fm);
131struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm); 129struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm);
132int tifm_register_driver(struct tifm_driver *drv); 130int tifm_register_driver(struct tifm_driver *drv);