From 8e02f8581cd2f9c12a03be7641d5c2c427170feb Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Fri, 8 Dec 2006 16:50:51 +1100 Subject: tifm_sd: restructure initialization, removal and command handling In order to support correct suspend and resume several changes were needed: 1. Switch from work_struct to tasklet for command handling. When device suspend is called workqueues are already frozen and can not be used. 2. Separate host initialization code from driver's probe and don't rely on interrupts for host initialization. This, in turn, addresses two problems: a) Resume needs to re-initialize the host, but can not assume that device interrupts were already re-armed. b) Previously, probe will return successfully before really knowing the state of the host, as host interrupts were not armed in time. Now it uses polling to determine the real host state before returning. 3. Separate termination code from driver's remove. Termination may be caused by resume, if media changed type or became unavailable during suspend. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman --- drivers/misc/tifm_7xx1.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/misc/tifm_7xx1.c') diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 2ab7add78f94..50c4cdabb654 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -201,11 +201,12 @@ static void tifm_7xx1_insert_media(struct work_struct *work) fm->max_sockets == 2); if (media_id) { ok_to_register = 0; - new_sock = tifm_alloc_device(fm, cnt); + new_sock = tifm_alloc_device(fm); if (new_sock) { new_sock->addr = tifm_7xx1_sock_addr(fm->addr, cnt); new_sock->media_id = media_id; + new_sock->socket_id = cnt; switch (media_id) { case 1: card_name = "xd"; -- cgit v1.2.2 From 50743f4cb1d655c7fbe25af58a9d0db6bf76d687 Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Mon, 11 Dec 2006 01:55:30 +1100 Subject: Remove unused return value from signal_irq callback Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman --- drivers/misc/tifm_7xx1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/misc/tifm_7xx1.c') diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 50c4cdabb654..375b56742f2b 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -13,7 +13,7 @@ #include #define DRIVER_NAME "tifm_7xx1" -#define DRIVER_VERSION "0.6" +#define DRIVER_VERSION "0.7" static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) { @@ -91,7 +91,7 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) if (fm->sockets[cnt]) { if (sock_irq_status && fm->sockets[cnt]->signal_irq) - sock_irq_status = fm->sockets[cnt]-> + fm->sockets[cnt]-> signal_irq(fm->sockets[cnt], sock_irq_status); -- cgit v1.2.2 From 217334d14d28e6a671e6dd2c7a35c9070b0721ea Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Mon, 11 Dec 2006 01:55:31 +1100 Subject: Add dummy_signal_irq function to save check in ISR Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman --- drivers/misc/tifm_7xx1.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/misc/tifm_7xx1.c') diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 375b56742f2b..7fbf5d58bfc5 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -71,6 +71,7 @@ static void tifm_7xx1_remove_media(struct work_struct *work) static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) { struct tifm_adapter *fm = dev_id; + struct tifm_dev *sock; unsigned int irq_status; unsigned int sock_irq_status, cnt; @@ -85,15 +86,13 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); for (cnt = 0; cnt < fm->max_sockets; cnt++) { + sock = fm->sockets[cnt]; sock_irq_status = (irq_status >> cnt) & (TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK); - if (fm->sockets[cnt]) { - if (sock_irq_status && - fm->sockets[cnt]->signal_irq) - fm->sockets[cnt]-> - signal_irq(fm->sockets[cnt], - sock_irq_status); + if (sock) { + if (sock_irq_status) + sock->signal_irq(sock, sock_irq_status); if (irq_status & (1 << cnt)) fm->remove_mask |= 1 << cnt; -- cgit v1.2.2 From 1499ead31ede528a657c50761c4780c40f929d6d Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Mon, 11 Dec 2006 01:55:32 +1100 Subject: tifm_7xx1: simplify eject function Eject function can take advantage of the socket_id field instead of explicit pointer comparison. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman --- drivers/misc/tifm_7xx1.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/misc/tifm_7xx1.c') diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 7fbf5d58bfc5..24b20a417a23 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -17,18 +17,12 @@ static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) { - int cnt; unsigned long flags; spin_lock_irqsave(&fm->lock, flags); if (!fm->inhibit_new_cards) { - for (cnt = 0; cnt < fm->max_sockets; cnt++) { - if (fm->sockets[cnt] == sock) { - fm->remove_mask |= (1 << cnt); - queue_work(fm->wq, &fm->media_remover); - break; - } - } + fm->remove_mask |= 1 << sock->socket_id; + queue_work(fm->wq, &fm->media_remover); } spin_unlock_irqrestore(&fm->lock, flags); } -- cgit v1.2.2 From 6412d927313f08808d61b7efba8da43717d4e8d2 Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Mon, 11 Dec 2006 01:55:33 +1100 Subject: tifm_7xx1: Merge media insert and media remove functions Hardware does not say whether card was inserted or removed when reporting socket events. Moreover, during suspend, media can be removed or switched to some other card type without notification. Therefore, for each socket in the change set the following is performed: 1. If there's active device in the socket it's unregistered 2. Media detection is performed 3. If detection recognizes supportable media, new device is registered This patch also alters some macros and variable names to enhance clarity. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman --- drivers/misc/tifm_7xx1.c | 254 +++++++++++++++++++++++------------------------ 1 file changed, 126 insertions(+), 128 deletions(-) (limited to 'drivers/misc/tifm_7xx1.c') diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 24b20a417a23..5ab81dd37857 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -21,47 +21,12 @@ static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) spin_lock_irqsave(&fm->lock, flags); if (!fm->inhibit_new_cards) { - fm->remove_mask |= 1 << sock->socket_id; - queue_work(fm->wq, &fm->media_remover); + fm->socket_change_set |= 1 << sock->socket_id; + queue_work(fm->wq, &fm->media_switcher); } spin_unlock_irqrestore(&fm->lock, flags); } -static void tifm_7xx1_remove_media(struct work_struct *work) -{ - struct tifm_adapter *fm = - container_of(work, struct tifm_adapter, media_remover); - unsigned long flags; - int cnt; - struct tifm_dev *sock; - - if (!class_device_get(&fm->cdev)) - return; - spin_lock_irqsave(&fm->lock, flags); - for (cnt = 0; cnt < fm->max_sockets; cnt++) { - if (fm->sockets[cnt] && (fm->remove_mask & (1 << cnt))) { - printk(KERN_INFO DRIVER_NAME - ": demand removing card from socket %d\n", cnt); - sock = fm->sockets[cnt]; - fm->sockets[cnt] = NULL; - fm->remove_mask &= ~(1 << cnt); - - writel(0x0e00, sock->addr + SOCK_CONTROL); - - writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, - fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, - fm->addr + FM_SET_INTERRUPT_ENABLE); - - spin_unlock_irqrestore(&fm->lock, flags); - device_unregister(&sock->dev); - spin_lock_irqsave(&fm->lock, flags); - } - } - spin_unlock_irqrestore(&fm->lock, flags); - class_device_put(&fm->cdev); -} - static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) { struct tifm_adapter *fm = dev_id; @@ -79,32 +44,27 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) if (irq_status & TIFM_IRQ_ENABLE) { writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - for (cnt = 0; cnt < fm->max_sockets; cnt++) { + for (cnt = 0; cnt < fm->num_sockets; cnt++) { sock = fm->sockets[cnt]; - sock_irq_status = (irq_status >> cnt) & - (TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK); - - if (sock) { - if (sock_irq_status) - sock->signal_irq(sock, sock_irq_status); + sock_irq_status = (irq_status >> cnt) + & (TIFM_IRQ_FIFOMASK(1) + | TIFM_IRQ_CARDMASK(1)); - if (irq_status & (1 << cnt)) - fm->remove_mask |= 1 << cnt; - } else { - if (irq_status & (1 << cnt)) - fm->insert_mask |= 1 << cnt; - } + if (sock && sock_irq_status) + sock->signal_irq(sock, sock_irq_status); } + + fm->socket_change_set |= irq_status + & ((1 << fm->num_sockets) - 1); } writel(irq_status, fm->addr + FM_INTERRUPT_STATUS); if (!fm->inhibit_new_cards) { - if (!fm->remove_mask && !fm->insert_mask) { + if (!fm->socket_change_set) { writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); } else { - queue_work(fm->wq, &fm->media_remover); - queue_work(fm->wq, &fm->media_inserter); + queue_work(fm->wq, &fm->media_switcher); } } @@ -163,84 +123,125 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num) return base_addr + ((sock_num + 1) << 10); } -static void tifm_7xx1_insert_media(struct work_struct *work) +static void tifm_7xx1_switch_media(struct work_struct *work) { struct tifm_adapter *fm = - container_of(work, struct tifm_adapter, media_inserter); + container_of(work, struct tifm_adapter, media_switcher); unsigned long flags; tifm_media_id media_id; char *card_name = "xx"; - int cnt, ok_to_register; - unsigned int insert_mask; - struct tifm_dev *new_sock = NULL; + int cnt; + struct tifm_dev *sock; + unsigned int socket_change_set; if (!class_device_get(&fm->cdev)) return; - spin_lock_irqsave(&fm->lock, flags); - insert_mask = fm->insert_mask; - fm->insert_mask = 0; - if (fm->inhibit_new_cards) { + + while (1) { + spin_lock_irqsave(&fm->lock, flags); + socket_change_set = fm->socket_change_set; + fm->socket_change_set = 0; + + dev_dbg(fm->dev, "checking media set %x\n", + socket_change_set); + + if (fm->inhibit_new_cards) + socket_change_set = (1 << fm->num_sockets) - 1; spin_unlock_irqrestore(&fm->lock, flags); - class_device_put(&fm->cdev); - return; - } - spin_unlock_irqrestore(&fm->lock, flags); - for (cnt = 0; cnt < fm->max_sockets; cnt++) { - if (!(insert_mask & (1 << cnt))) - continue; - - media_id = tifm_7xx1_toggle_sock_power(tifm_7xx1_sock_addr(fm->addr, cnt), - fm->max_sockets == 2); - if (media_id) { - ok_to_register = 0; - new_sock = tifm_alloc_device(fm); - if (new_sock) { - new_sock->addr = tifm_7xx1_sock_addr(fm->addr, - cnt); - new_sock->media_id = media_id; - new_sock->socket_id = cnt; - switch (media_id) { - case 1: - card_name = "xd"; - break; - case 2: - card_name = "ms"; - break; - case 3: - card_name = "sd"; - break; - default: - break; - } - snprintf(new_sock->dev.bus_id, BUS_ID_SIZE, - "tifm_%s%u:%u", card_name, fm->id, cnt); + if (!socket_change_set) + break; + + spin_lock_irqsave(&fm->lock, flags); + for (cnt = 0; cnt < fm->num_sockets; cnt++) { + if (!(socket_change_set & (1 << cnt))) + continue; + sock = fm->sockets[cnt]; + if (sock) { printk(KERN_INFO DRIVER_NAME - ": %s card detected in socket %d\n", - card_name, cnt); + ": demand removing card from socket %d\n", + cnt); + fm->sockets[cnt] = NULL; + spin_unlock_irqrestore(&fm->lock, flags); + device_unregister(&sock->dev); spin_lock_irqsave(&fm->lock, flags); - if (!fm->sockets[cnt]) { - fm->sockets[cnt] = new_sock; - ok_to_register = 1; + writel(0x0e00, + tifm_7xx1_sock_addr(fm->addr, cnt) + + SOCK_CONTROL); + } + if (fm->inhibit_new_cards) + continue; + + spin_unlock_irqrestore(&fm->lock, flags); + media_id = tifm_7xx1_toggle_sock_power( + tifm_7xx1_sock_addr(fm->addr, cnt), + fm->num_sockets == 2); + if (media_id) { + sock = tifm_alloc_device(fm); + if (sock) { + sock->addr = tifm_7xx1_sock_addr(fm->addr, + cnt); + sock->media_id = media_id; + sock->socket_id = cnt; + switch (media_id) { + case 1: + card_name = "xd"; + break; + case 2: + card_name = "ms"; + break; + case 3: + card_name = "sd"; + break; + default: + tifm_free_device(&sock->dev); + spin_lock_irqsave(&fm->lock, flags); + continue; + } + snprintf(sock->dev.bus_id, BUS_ID_SIZE, + "tifm_%s%u:%u", card_name, fm->id, cnt); + printk(KERN_INFO DRIVER_NAME + ": %s card detected in socket %d\n", + card_name, cnt); + if (!device_register(&sock->dev)) { + spin_lock_irqsave(&fm->lock, flags); + if (!fm->sockets[cnt]) { + fm->sockets[cnt] = sock; + sock = NULL; + } + spin_unlock_irqrestore(&fm->lock, flags); + } + if (sock) + tifm_free_device(&sock->dev); } + spin_lock_irqsave(&fm->lock, flags); + } + } + + if (!fm->inhibit_new_cards) { + writel(TIFM_IRQ_FIFOMASK(socket_change_set) + | TIFM_IRQ_CARDMASK(socket_change_set), + fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + writel(TIFM_IRQ_FIFOMASK(socket_change_set) + | TIFM_IRQ_CARDMASK(socket_change_set), + fm->addr + FM_SET_INTERRUPT_ENABLE); + writel(TIFM_IRQ_ENABLE, + fm->addr + FM_SET_INTERRUPT_ENABLE); + spin_unlock_irqrestore(&fm->lock, flags); + break; + } else { + for (cnt = 0; cnt < fm->num_sockets; cnt++) { + if (fm->sockets[cnt]) + fm->socket_change_set |= 1 << cnt; + } + if (!fm->socket_change_set) { + spin_unlock_irqrestore(&fm->lock, flags); + break; + } else { spin_unlock_irqrestore(&fm->lock, flags); - if (!ok_to_register || - device_register(&new_sock->dev)) { - spin_lock_irqsave(&fm->lock, flags); - fm->sockets[cnt] = NULL; - spin_unlock_irqrestore(&fm->lock, - flags); - tifm_free_device(&new_sock->dev); - } } } - writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, - fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, - fm->addr + FM_SET_INTERRUPT_ENABLE); } - - writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); class_device_put(&fm->cdev); } @@ -251,13 +252,12 @@ static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state) spin_lock_irqsave(&fm->lock, flags); fm->inhibit_new_cards = 1; - fm->remove_mask = 0xf; - fm->insert_mask = 0; + fm->socket_change_set = 0xf; writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); spin_unlock_irqrestore(&fm->lock, flags); flush_workqueue(fm->wq); - tifm_7xx1_remove_media(&fm->media_remover); + tifm_7xx1_switch_media(&fm->media_switcher); pci_set_power_state(dev, PCI_D3hot); pci_disable_device(dev); @@ -279,9 +279,9 @@ static int tifm_7xx1_resume(struct pci_dev *dev) fm->inhibit_new_cards = 0; writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS); writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK, + writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), fm->addr + FM_SET_INTERRUPT_ENABLE); - fm->insert_mask = 0xf; + fm->socket_change_set = 0xf; spin_unlock_irqrestore(&fm->lock, flags); return 0; } @@ -318,14 +318,13 @@ static int tifm_7xx1_probe(struct pci_dev *dev, } fm->dev = &dev->dev; - fm->max_sockets = (dev->device == 0x803B) ? 2 : 4; - fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->max_sockets, + fm->num_sockets = (dev->device == 0x803B) ? 2 : 4; + fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets, GFP_KERNEL); if (!fm->sockets) goto err_out_free; - INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media); - INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media); + INIT_WORK(&fm->media_switcher, tifm_7xx1_switch_media); fm->eject = tifm_7xx1_eject; pci_set_drvdata(dev, fm); @@ -343,10 +342,10 @@ static int tifm_7xx1_probe(struct pci_dev *dev, goto err_out_irq; writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK, + writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), fm->addr + FM_SET_INTERRUPT_ENABLE); - fm->insert_mask = 0xf; + fm->socket_change_set = 0xf; return 0; @@ -373,14 +372,13 @@ static void tifm_7xx1_remove(struct pci_dev *dev) spin_lock_irqsave(&fm->lock, flags); fm->inhibit_new_cards = 1; - fm->remove_mask = 0xf; - fm->insert_mask = 0; + fm->socket_change_set = 0xf; writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); spin_unlock_irqrestore(&fm->lock, flags); flush_workqueue(fm->wq); - tifm_7xx1_remove_media(&fm->media_remover); + tifm_7xx1_switch_media(&fm->media_switcher); writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); free_irq(dev->irq, fm); -- cgit v1.2.2 From 7146f0d3bd2bcd0100a5db54f4ba9edc1042fe01 Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Mon, 18 Dec 2006 14:20:06 +1100 Subject: tifm_7xx1: switch from workqueue to kthread As there's only one work item (media_switcher) to handle and it's effectively serialized with itself, I found it more convenient to use kthread instead of workqueue. This also allows for a working implementation of suspend/resume, which were totally broken in the past version. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman --- drivers/misc/tifm_7xx1.c | 151 ++++++++++++++++++++++++++++------------------- 1 file changed, 89 insertions(+), 62 deletions(-) (limited to 'drivers/misc/tifm_7xx1.c') 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 @@ #include #include +#include #define DRIVER_NAME "tifm_7xx1" #define DRIVER_VERSION "0.7" @@ -20,10 +21,8 @@ static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) unsigned long flags; spin_lock_irqsave(&fm->lock, flags); - if (!fm->inhibit_new_cards) { - fm->socket_change_set |= 1 << sock->socket_id; - queue_work(fm->wq, &fm->media_switcher); - } + fm->socket_change_set |= 1 << sock->socket_id; + wake_up_all(&fm->change_set_notify); spin_unlock_irqrestore(&fm->lock, flags); } @@ -59,14 +58,10 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) } writel(irq_status, fm->addr + FM_INTERRUPT_STATUS); - if (!fm->inhibit_new_cards) { - if (!fm->socket_change_set) { - writel(TIFM_IRQ_ENABLE, - fm->addr + FM_SET_INTERRUPT_ENABLE); - } else { - queue_work(fm->wq, &fm->media_switcher); - } - } + if (!fm->socket_change_set) + writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); + else + wake_up_all(&fm->change_set_notify); spin_unlock(&fm->lock); return IRQ_HANDLED; @@ -123,21 +118,22 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num) return base_addr + ((sock_num + 1) << 10); } -static void tifm_7xx1_switch_media(struct work_struct *work) +static int tifm_7xx1_switch_media(void *data) { - struct tifm_adapter *fm = - container_of(work, struct tifm_adapter, media_switcher); + struct tifm_adapter *fm = data; unsigned long flags; tifm_media_id media_id; char *card_name = "xx"; - int cnt; + int cnt, rc; struct tifm_dev *sock; unsigned int socket_change_set; - if (!class_device_get(&fm->cdev)) - return; - while (1) { + rc = wait_event_interruptible(fm->change_set_notify, + fm->socket_change_set); + if (rc == -ERESTARTSYS) + try_to_freeze(); + spin_lock_irqsave(&fm->lock, flags); socket_change_set = fm->socket_change_set; fm->socket_change_set = 0; @@ -145,12 +141,12 @@ static void tifm_7xx1_switch_media(struct work_struct *work) dev_dbg(fm->dev, "checking media set %x\n", socket_change_set); - if (fm->inhibit_new_cards) + if (kthread_should_stop()) socket_change_set = (1 << fm->num_sockets) - 1; spin_unlock_irqrestore(&fm->lock, flags); if (!socket_change_set) - break; + continue; spin_lock_irqsave(&fm->lock, flags); for (cnt = 0; cnt < fm->num_sockets; cnt++) { @@ -169,7 +165,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work) tifm_7xx1_sock_addr(fm->addr, cnt) + SOCK_CONTROL); } - if (fm->inhibit_new_cards) + if (kthread_should_stop()) continue; spin_unlock_irqrestore(&fm->lock, flags); @@ -218,7 +214,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work) } } - if (!fm->inhibit_new_cards) { + if (!kthread_should_stop()) { writel(TIFM_IRQ_FIFOMASK(socket_change_set) | TIFM_IRQ_CARDMASK(socket_change_set), fm->addr + FM_CLEAR_INTERRUPT_ENABLE); @@ -228,7 +224,6 @@ static void tifm_7xx1_switch_media(struct work_struct *work) writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); spin_unlock_irqrestore(&fm->lock, flags); - break; } else { for (cnt = 0; cnt < fm->num_sockets; cnt++) { if (fm->sockets[cnt]) @@ -236,56 +231,93 @@ static void tifm_7xx1_switch_media(struct work_struct *work) } if (!fm->socket_change_set) { spin_unlock_irqrestore(&fm->lock, flags); - break; + return 0; } else { spin_unlock_irqrestore(&fm->lock, flags); } } } - class_device_put(&fm->cdev); + return 0; } +#ifdef CONFIG_PM + static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state) { - struct tifm_adapter *fm = pci_get_drvdata(dev); - unsigned long flags; + dev_dbg(&dev->dev, "suspending host\n"); - spin_lock_irqsave(&fm->lock, flags); - fm->inhibit_new_cards = 1; - fm->socket_change_set = 0xf; - writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - spin_unlock_irqrestore(&fm->lock, flags); - flush_workqueue(fm->wq); - - tifm_7xx1_switch_media(&fm->media_switcher); - - pci_set_power_state(dev, PCI_D3hot); - pci_disable_device(dev); - pci_save_state(dev); + pci_save_state(dev); + pci_enable_wake(dev, pci_choose_state(dev, state), 0); + pci_disable_device(dev); + pci_set_power_state(dev, pci_choose_state(dev, state)); return 0; } static int tifm_7xx1_resume(struct pci_dev *dev) { struct tifm_adapter *fm = pci_get_drvdata(dev); + int cnt, rc; unsigned long flags; + tifm_media_id new_ids[fm->num_sockets]; + pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); - pci_enable_device(dev); - pci_set_power_state(dev, PCI_D0); - pci_set_master(dev); + rc = pci_enable_device(dev); + if (rc) + return rc; + pci_set_master(dev); + + dev_dbg(&dev->dev, "resuming host\n"); + for (cnt = 0; cnt < fm->num_sockets; cnt++) + new_ids[cnt] = tifm_7xx1_toggle_sock_power( + tifm_7xx1_sock_addr(fm->addr, cnt), + fm->num_sockets == 2); spin_lock_irqsave(&fm->lock, flags); - fm->inhibit_new_cards = 0; - writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS); - writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + fm->socket_change_set = 0; + for (cnt = 0; cnt < fm->num_sockets; cnt++) { + if (fm->sockets[cnt]) { + if (fm->sockets[cnt]->media_id == new_ids[cnt]) + fm->socket_change_set |= 1 << cnt; + + fm->sockets[cnt]->media_id = new_ids[cnt]; + } + } + writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), - fm->addr + FM_SET_INTERRUPT_ENABLE); - fm->socket_change_set = 0xf; + fm->addr + FM_SET_INTERRUPT_ENABLE); + if (!fm->socket_change_set) { + spin_unlock_irqrestore(&fm->lock, flags); + return 0; + } else { + fm->socket_change_set = 0; + spin_unlock_irqrestore(&fm->lock, flags); + } + + wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ); + + spin_lock_irqsave(&fm->lock, flags); + 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, + fm->addr + FM_SET_INTERRUPT_ENABLE); + fm->socket_change_set = 0; + spin_unlock_irqrestore(&fm->lock, flags); return 0; } +#else + +#define tifm_7xx1_suspend NULL +#define tifm_7xx1_resume NULL + +#endif /* CONFIG_PM */ + static int tifm_7xx1_probe(struct pci_dev *dev, const struct pci_device_id *dev_id) { @@ -324,7 +356,6 @@ static int tifm_7xx1_probe(struct pci_dev *dev, if (!fm->sockets) goto err_out_free; - INIT_WORK(&fm->media_switcher, tifm_7xx1_switch_media); fm->eject = tifm_7xx1_eject; pci_set_drvdata(dev, fm); @@ -337,16 +368,15 @@ static int tifm_7xx1_probe(struct pci_dev *dev, if (rc) goto err_out_unmap; - rc = tifm_add_adapter(fm); + init_waitqueue_head(&fm->change_set_notify); + rc = tifm_add_adapter(fm, tifm_7xx1_switch_media); if (rc) goto err_out_irq; writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), fm->addr + FM_SET_INTERRUPT_ENABLE); - - fm->socket_change_set = 0xf; - + wake_up_process(fm->media_switcher); return 0; err_out_irq: @@ -370,18 +400,15 @@ static void tifm_7xx1_remove(struct pci_dev *dev) struct tifm_adapter *fm = pci_get_drvdata(dev); unsigned long flags; + writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + mmiowb(); + free_irq(dev->irq, fm); + spin_lock_irqsave(&fm->lock, flags); - fm->inhibit_new_cards = 1; - fm->socket_change_set = 0xf; - writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + fm->socket_change_set = (1 << fm->num_sockets) - 1; spin_unlock_irqrestore(&fm->lock, flags); - flush_workqueue(fm->wq); - - tifm_7xx1_switch_media(&fm->media_switcher); - - writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - free_irq(dev->irq, fm); + kthread_stop(fm->media_switcher); tifm_remove_adapter(fm); -- cgit v1.2.2 From b5ad6761533c3f7e97c93b2333a0f88490d44f36 Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Mon, 11 Dec 2006 01:55:35 +1100 Subject: tifm_7xx1: recognize device 0xac8f as supported This patch also adds symbolic defines for supported pci ids. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman --- drivers/misc/tifm_7xx1.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/misc/tifm_7xx1.c') diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index d3e8ff46c237..ea6ad9f2d245 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -350,7 +350,8 @@ static int tifm_7xx1_probe(struct pci_dev *dev, } fm->dev = &dev->dev; - fm->num_sockets = (dev->device == 0x803B) ? 2 : 4; + fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM) + ? 4 : 2; fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets, GFP_KERNEL); if (!fm->sockets) @@ -423,10 +424,12 @@ static void tifm_7xx1_remove(struct pci_dev *dev) } static struct pci_device_id tifm_7xx1_pci_tbl [] = { - { PCI_VENDOR_ID_TI, 0x8033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - 0 }, /* xx21 - the one I have */ - { PCI_VENDOR_ID_TI, 0x803B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - 0 }, /* xx12 - should be also supported */ + { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11_FM, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, /* xx21 - the one I have */ + { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12_FM, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX20_FM, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, { } }; -- cgit v1.2.2 From 8b40adab9c6cb63cede72c3ce3c3fee1157719e0 Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Mon, 11 Dec 2006 01:55:36 +1100 Subject: tifm_7xx1: prettify Fix some spaces and tabs. No semantic changes are introduced. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman --- drivers/misc/tifm_7xx1.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) (limited to 'drivers/misc/tifm_7xx1.c') diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index ea6ad9f2d245..e21e490fedb0 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -43,7 +43,7 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) if (irq_status & TIFM_IRQ_ENABLE) { writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - for (cnt = 0; cnt < fm->num_sockets; cnt++) { + for (cnt = 0; cnt < fm->num_sockets; cnt++) { sock = fm->sockets[cnt]; sock_irq_status = (irq_status >> cnt) & (TIFM_IRQ_FIFOMASK(1) @@ -53,8 +53,8 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) sock->signal_irq(sock, sock_irq_status); } - fm->socket_change_set |= irq_status - & ((1 << fm->num_sockets) - 1); + fm->socket_change_set |= irq_status + & ((1 << fm->num_sockets) - 1); } writel(irq_status, fm->addr + FM_INTERRUPT_STATUS); @@ -67,7 +67,8 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is_x2) +static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, + int is_x2) { unsigned int s_state; int cnt; @@ -75,8 +76,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is writel(0x0e00, sock_addr + SOCK_CONTROL); for (cnt = 0; cnt < 100; cnt++) { - if (!(TIFM_SOCK_STATE_POWERED & - readl(sock_addr + SOCK_PRESENT_STATE))) + if (!(TIFM_SOCK_STATE_POWERED + & readl(sock_addr + SOCK_PRESENT_STATE))) break; msleep(10); } @@ -99,8 +100,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is } for (cnt = 0; cnt < 100; cnt++) { - if ((TIFM_SOCK_STATE_POWERED & - readl(sock_addr + SOCK_PRESENT_STATE))) + if ((TIFM_SOCK_STATE_POWERED + & readl(sock_addr + SOCK_PRESENT_STATE))) break; msleep(10); } @@ -176,7 +177,7 @@ static int tifm_7xx1_switch_media(void *data) sock = tifm_alloc_device(fm); if (sock) { sock->addr = tifm_7xx1_sock_addr(fm->addr, - cnt); + cnt); sock->media_id = media_id; sock->socket_id = cnt; switch (media_id) { @@ -195,10 +196,11 @@ static int tifm_7xx1_switch_media(void *data) continue; } snprintf(sock->dev.bus_id, BUS_ID_SIZE, - "tifm_%s%u:%u", card_name, fm->id, cnt); + "tifm_%s%u:%u", card_name, + fm->id, cnt); printk(KERN_INFO DRIVER_NAME - ": %s card detected in socket %d\n", - card_name, cnt); + ": %s card detected in socket %d\n", + card_name, cnt); if (!device_register(&sock->dev)) { spin_lock_irqsave(&fm->lock, flags); if (!fm->sockets[cnt]) { @@ -319,7 +321,7 @@ static int tifm_7xx1_resume(struct pci_dev *dev) #endif /* CONFIG_PM */ static int tifm_7xx1_probe(struct pci_dev *dev, - const struct pci_device_id *dev_id) + const struct pci_device_id *dev_id) { struct tifm_adapter *fm; int pci_dev_busy = 0; @@ -353,7 +355,7 @@ static int tifm_7xx1_probe(struct pci_dev *dev, fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM) ? 4 : 2; fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets, - GFP_KERNEL); + GFP_KERNEL); if (!fm->sockets) goto err_out_free; @@ -361,7 +363,7 @@ static int tifm_7xx1_probe(struct pci_dev *dev, pci_set_drvdata(dev, fm); fm->addr = ioremap(pci_resource_start(dev, 0), - pci_resource_len(dev, 0)); + pci_resource_len(dev, 0)); if (!fm->addr) goto err_out_free; @@ -376,7 +378,7 @@ static int tifm_7xx1_probe(struct pci_dev *dev, writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), - fm->addr + FM_SET_INTERRUPT_ENABLE); + fm->addr + FM_SET_INTERRUPT_ENABLE); wake_up_process(fm->media_switcher); return 0; -- cgit v1.2.2