aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/tifm_7xx1.c
diff options
context:
space:
mode:
authorAlex Dubov <oakad@yahoo.com>2007-04-12 02:59:19 -0400
committerPierre Ossman <drzeus@drzeus.cx>2007-05-01 07:04:13 -0400
commit88de1b2fed2bbe9eb1b7310195be84cf143efb4f (patch)
tree4f52fe092254b8992a19797860edc8889c08a1f5 /drivers/misc/tifm_7xx1.c
parent2428a8fe2261e901e058d9ea8b6ed7e1b4268b79 (diff)
tifm_7xx1: fix adapter resume function
Fixes to the adapter resume function to correctly handle all possible cases: 1. Card is removed during suspend 2. Card is inserted during suspend into previously empty socket 3. Card is replaced during suspend by same or different media type card. 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.c58
1 files changed, 31 insertions, 27 deletions
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
index 356386904a5..eafa5575f31 100644
--- a/drivers/misc/tifm_7xx1.c
+++ b/drivers/misc/tifm_7xx1.c
@@ -220,7 +220,8 @@ static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
220static int tifm_7xx1_resume(struct pci_dev *dev) 220static int tifm_7xx1_resume(struct pci_dev *dev)
221{ 221{
222 struct tifm_adapter *fm = pci_get_drvdata(dev); 222 struct tifm_adapter *fm = pci_get_drvdata(dev);
223 int cnt, rc; 223 int rc;
224 unsigned int good_sockets = 0, bad_sockets = 0;
224 unsigned long flags; 225 unsigned long flags;
225 unsigned char new_ids[fm->num_sockets]; 226 unsigned char new_ids[fm->num_sockets];
226 DECLARE_COMPLETION_ONSTACK(finish_resume); 227 DECLARE_COMPLETION_ONSTACK(finish_resume);
@@ -234,46 +235,49 @@ static int tifm_7xx1_resume(struct pci_dev *dev)
234 235
235 dev_dbg(&dev->dev, "resuming host\n"); 236 dev_dbg(&dev->dev, "resuming host\n");
236 237
237 for (cnt = 0; cnt < fm->num_sockets; cnt++) 238 for (rc = 0; rc < fm->num_sockets; rc++)
238 new_ids[cnt] = tifm_7xx1_toggle_sock_power( 239 new_ids[rc] = tifm_7xx1_toggle_sock_power(
239 tifm_7xx1_sock_addr(fm->addr, cnt)); 240 tifm_7xx1_sock_addr(fm->addr, rc));
240 spin_lock_irqsave(&fm->lock, flags); 241 spin_lock_irqsave(&fm->lock, flags);
241 fm->socket_change_set = 0; 242 for (rc = 0; rc < fm->num_sockets; rc++) {
242 for (cnt = 0; cnt < fm->num_sockets; cnt++) { 243 if (fm->sockets[rc]) {
243 if (fm->sockets[cnt]) { 244 if (fm->sockets[rc]->type == new_ids[rc])
244 if (fm->sockets[cnt]->type == new_ids[cnt]) 245 good_sockets |= 1 << rc;
245 fm->socket_change_set |= 1 << cnt; 246 else
246 247 bad_sockets |= 1 << rc;
247 fm->sockets[cnt]->type = new_ids[cnt];
248 } 248 }
249 } 249 }
250 250
251 writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), 251 writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
252 fm->addr + FM_SET_INTERRUPT_ENABLE); 252 fm->addr + FM_SET_INTERRUPT_ENABLE);
253 if (!fm->socket_change_set) { 253 dev_dbg(&dev->dev, "change sets on resume: good %x, bad %x\n",
254 spin_unlock_irqrestore(&fm->lock, flags); 254 good_sockets, bad_sockets);
255 return 0; 255
256 } else { 256 fm->socket_change_set = 0;
257 fm->socket_change_set = 0; 257 if (good_sockets) {
258 fm->finish_me = &finish_resume; 258 fm->finish_me = &finish_resume;
259 spin_unlock_irqrestore(&fm->lock, flags); 259 spin_unlock_irqrestore(&fm->lock, flags);
260 rc = wait_for_completion_timeout(&finish_resume, HZ);
261 dev_dbg(&dev->dev, "wait returned %d\n", rc);
262 writel(TIFM_IRQ_FIFOMASK(good_sockets)
263 | TIFM_IRQ_CARDMASK(good_sockets),
264 fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
265 writel(TIFM_IRQ_FIFOMASK(good_sockets)
266 | TIFM_IRQ_CARDMASK(good_sockets),
267 fm->addr + FM_SET_INTERRUPT_ENABLE);
268 spin_lock_irqsave(&fm->lock, flags);
269 fm->finish_me = NULL;
270 fm->socket_change_set ^= good_sockets & fm->socket_change_set;
260 } 271 }
261 272
262 wait_for_completion_timeout(&finish_resume, HZ); 273 fm->socket_change_set |= bad_sockets;
274 if (fm->socket_change_set)
275 tifm_queue_work(&fm->media_switcher);
263 276
264 spin_lock_irqsave(&fm->lock, flags); 277 spin_unlock_irqrestore(&fm->lock, flags);
265 fm->finish_me = NULL;
266 writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
267 | TIFM_IRQ_CARDMASK(fm->socket_change_set),
268 fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
269 writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
270 | TIFM_IRQ_CARDMASK(fm->socket_change_set),
271 fm->addr + FM_SET_INTERRUPT_ENABLE);
272 writel(TIFM_IRQ_ENABLE, 278 writel(TIFM_IRQ_ENABLE,
273 fm->addr + FM_SET_INTERRUPT_ENABLE); 279 fm->addr + FM_SET_INTERRUPT_ENABLE);
274 fm->socket_change_set = 0;
275 280
276 spin_unlock_irqrestore(&fm->lock, flags);
277 return 0; 281 return 0;
278} 282}
279 283