Commit 88de1b2f authored by Alex Dubov's avatar Alex Dubov Committed by Pierre Ossman

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: default avatarAlex Dubov <oakad@yahoo.com>
Signed-off-by: default avatarPierre Ossman <drzeus@drzeus.cx>
parent 2428a8fe
...@@ -220,7 +220,8 @@ static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state) ...@@ -220,7 +220,8 @@ static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
static int tifm_7xx1_resume(struct pci_dev *dev) static int tifm_7xx1_resume(struct pci_dev *dev)
{ {
struct tifm_adapter *fm = pci_get_drvdata(dev); struct tifm_adapter *fm = pci_get_drvdata(dev);
int cnt, rc; int rc;
unsigned int good_sockets = 0, bad_sockets = 0;
unsigned long flags; unsigned long flags;
unsigned char new_ids[fm->num_sockets]; unsigned char new_ids[fm->num_sockets];
DECLARE_COMPLETION_ONSTACK(finish_resume); DECLARE_COMPLETION_ONSTACK(finish_resume);
...@@ -234,46 +235,49 @@ static int tifm_7xx1_resume(struct pci_dev *dev) ...@@ -234,46 +235,49 @@ static int tifm_7xx1_resume(struct pci_dev *dev)
dev_dbg(&dev->dev, "resuming host\n"); dev_dbg(&dev->dev, "resuming host\n");
for (cnt = 0; cnt < fm->num_sockets; cnt++) for (rc = 0; rc < fm->num_sockets; rc++)
new_ids[cnt] = tifm_7xx1_toggle_sock_power( new_ids[rc] = tifm_7xx1_toggle_sock_power(
tifm_7xx1_sock_addr(fm->addr, cnt)); tifm_7xx1_sock_addr(fm->addr, rc));
spin_lock_irqsave(&fm->lock, flags); spin_lock_irqsave(&fm->lock, flags);
fm->socket_change_set = 0; for (rc = 0; rc < fm->num_sockets; rc++) {
for (cnt = 0; cnt < fm->num_sockets; cnt++) { if (fm->sockets[rc]) {
if (fm->sockets[cnt]) { if (fm->sockets[rc]->type == new_ids[rc])
if (fm->sockets[cnt]->type == new_ids[cnt]) good_sockets |= 1 << rc;
fm->socket_change_set |= 1 << cnt; else
bad_sockets |= 1 << rc;
fm->sockets[cnt]->type = new_ids[cnt];
} }
} }
writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
fm->addr + FM_SET_INTERRUPT_ENABLE); fm->addr + FM_SET_INTERRUPT_ENABLE);
if (!fm->socket_change_set) { dev_dbg(&dev->dev, "change sets on resume: good %x, bad %x\n",
spin_unlock_irqrestore(&fm->lock, flags); good_sockets, bad_sockets);
return 0;
} else { fm->socket_change_set = 0;
fm->socket_change_set = 0; if (good_sockets) {
fm->finish_me = &finish_resume; fm->finish_me = &finish_resume;
spin_unlock_irqrestore(&fm->lock, flags); spin_unlock_irqrestore(&fm->lock, flags);
rc = wait_for_completion_timeout(&finish_resume, HZ);
dev_dbg(&dev->dev, "wait returned %d\n", rc);
writel(TIFM_IRQ_FIFOMASK(good_sockets)
| TIFM_IRQ_CARDMASK(good_sockets),
fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
writel(TIFM_IRQ_FIFOMASK(good_sockets)
| TIFM_IRQ_CARDMASK(good_sockets),
fm->addr + FM_SET_INTERRUPT_ENABLE);
spin_lock_irqsave(&fm->lock, flags);
fm->finish_me = NULL;
fm->socket_change_set ^= good_sockets & fm->socket_change_set;
} }
wait_for_completion_timeout(&finish_resume, HZ); fm->socket_change_set |= bad_sockets;
if (fm->socket_change_set)
tifm_queue_work(&fm->media_switcher);
spin_lock_irqsave(&fm->lock, flags); spin_unlock_irqrestore(&fm->lock, flags);
fm->finish_me = NULL;
writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
| TIFM_IRQ_CARDMASK(fm->socket_change_set),
fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
| TIFM_IRQ_CARDMASK(fm->socket_change_set),
fm->addr + FM_SET_INTERRUPT_ENABLE);
writel(TIFM_IRQ_ENABLE, writel(TIFM_IRQ_ENABLE,
fm->addr + FM_SET_INTERRUPT_ENABLE); fm->addr + FM_SET_INTERRUPT_ENABLE);
fm->socket_change_set = 0;
spin_unlock_irqrestore(&fm->lock, flags);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment