Skip to content

Commit

Permalink
tifm: replace per-adapter kthread with freezeable workqueue
Browse files Browse the repository at this point in the history
Freezeable workqueue makes sure that adapter work items (device insertions
and removals) would be handled after the system is fully resumed. Previously
this was achieved by explicit freezing of the kthread.

Signed-off-by: Alex Dubov <oakad@yahoo.com>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
  • Loading branch information
Alex Dubov authored and Pierre Ossman committed May 1, 2007
1 parent e23f2b8 commit 3540af8
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 76 deletions.
89 changes: 34 additions & 55 deletions drivers/misc/tifm_7xx1.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)

spin_lock_irqsave(&fm->lock, flags);
fm->socket_change_set |= 1 << sock->socket_id;
wake_up_all(&fm->change_set_notify);
tifm_queue_work(&fm->media_switcher);
spin_unlock_irqrestore(&fm->lock, flags);
}

Expand Down Expand Up @@ -64,10 +64,12 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
}
writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);

if (!fm->socket_change_set)
if (fm->finish_me)
complete_all(fm->finish_me);
else if (!fm->socket_change_set)
writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
else
wake_up_all(&fm->change_set_notify);
tifm_queue_work(&fm->media_switcher);

spin_unlock(&fm->lock);
return IRQ_HANDLED;
Expand Down Expand Up @@ -125,37 +127,29 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)
return base_addr + ((sock_num + 1) << 10);
}

static int tifm_7xx1_switch_media(void *data)
static void tifm_7xx1_switch_media(struct work_struct *work)
{
struct tifm_adapter *fm = data;
struct tifm_adapter *fm = container_of(work, struct tifm_adapter,
media_switcher);
unsigned long flags;
unsigned char media_id;
char *card_name = "xx";
int cnt, rc;
int cnt;
struct tifm_dev *sock;
unsigned int socket_change_set;

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;
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);
dev_dbg(fm->dev, "checking media set %x\n",
socket_change_set);

if (kthread_should_stop())
socket_change_set = (1 << fm->num_sockets) - 1;
if (!socket_change_set) {
spin_unlock_irqrestore(&fm->lock, flags);
return;
}

if (!socket_change_set)
continue;

spin_lock_irqsave(&fm->lock, flags);
for (cnt = 0; cnt < fm->num_sockets; cnt++) {
if (!(socket_change_set & (1 << cnt)))
continue;
Expand All @@ -172,8 +166,6 @@ static int tifm_7xx1_switch_media(void *data)
tifm_7xx1_sock_addr(fm->addr, cnt)
+ SOCK_CONTROL);
}
if (kthread_should_stop())
continue;

spin_unlock_irqrestore(&fm->lock, flags);
media_id = tifm_7xx1_toggle_sock_power(
Expand Down Expand Up @@ -222,30 +214,16 @@ static int tifm_7xx1_switch_media(void *data)
}
}

if (!kthread_should_stop()) {
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);
} 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);
return 0;
} else {
spin_unlock_irqrestore(&fm->lock, flags);
}
}
}
return 0;
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);
}

#ifdef CONFIG_PM
Expand All @@ -267,6 +245,7 @@ static int tifm_7xx1_resume(struct pci_dev *dev)
int cnt, rc;
unsigned long flags;
unsigned char new_ids[fm->num_sockets];
DECLARE_COMPLETION_ONSTACK(finish_resume);

pci_set_power_state(dev, PCI_D0);
pci_restore_state(dev);
Expand Down Expand Up @@ -299,12 +278,14 @@ static int tifm_7xx1_resume(struct pci_dev *dev)
return 0;
} else {
fm->socket_change_set = 0;
fm->finish_me = &finish_resume;
spin_unlock_irqrestore(&fm->lock, flags);
}

wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ);
wait_for_completion_timeout(&finish_resume, HZ);

spin_lock_irqsave(&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);
Expand Down Expand Up @@ -365,6 +346,7 @@ 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);

Expand All @@ -377,15 +359,14 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
if (rc)
goto err_out_unmap;

init_waitqueue_head(&fm->change_set_notify);
rc = tifm_add_adapter(fm, tifm_7xx1_switch_media);
rc = tifm_add_adapter(fm);
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);
wake_up_process(fm->media_switcher);

return 0;

err_out_irq:
Expand Down Expand Up @@ -417,8 +398,6 @@ static void tifm_7xx1_remove(struct pci_dev *dev)
fm->socket_change_set = (1 << fm->num_sockets) - 1;
spin_unlock_irqrestore(&fm->lock, flags);

kthread_stop(fm->media_switcher);

tifm_remove_adapter(fm);

pci_set_drvdata(dev, NULL);
Expand Down
51 changes: 34 additions & 17 deletions drivers/misc/tifm_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define DRIVER_NAME "tifm_core"
#define DRIVER_VERSION "0.8"

static struct workqueue_struct *workqueue;
static DEFINE_IDR(tifm_adapter_idr);
static DEFINE_SPINLOCK(tifm_adapter_lock);

Expand Down Expand Up @@ -184,8 +185,7 @@ void tifm_free_adapter(struct tifm_adapter *fm)
}
EXPORT_SYMBOL(tifm_free_adapter);

int tifm_add_adapter(struct tifm_adapter *fm,
int (*mediathreadfn)(void *data))
int tifm_add_adapter(struct tifm_adapter *fm)
{
int rc;

Expand All @@ -197,23 +197,21 @@ int tifm_add_adapter(struct tifm_adapter *fm,
spin_unlock(&tifm_adapter_lock);
if (!rc) {
snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
fm->media_switcher = kthread_create(mediathreadfn,
fm, "tifm/%u", fm->id);
rc = class_device_add(&fm->cdev);

if (!IS_ERR(fm->media_switcher))
return class_device_add(&fm->cdev);

spin_lock(&tifm_adapter_lock);
idr_remove(&tifm_adapter_idr, fm->id);
spin_unlock(&tifm_adapter_lock);
rc = -ENOMEM;
if (rc) {
spin_lock(&tifm_adapter_lock);
idr_remove(&tifm_adapter_idr, fm->id);
spin_unlock(&tifm_adapter_lock);
}
}
return rc;
}
EXPORT_SYMBOL(tifm_add_adapter);

void tifm_remove_adapter(struct tifm_adapter *fm)
{
flush_workqueue(workqueue);
class_device_del(&fm->cdev);

spin_lock(&tifm_adapter_lock);
Expand Down Expand Up @@ -267,6 +265,12 @@ void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
}
EXPORT_SYMBOL(tifm_unmap_sg);

void tifm_queue_work(struct work_struct *work)
{
queue_work(workqueue, work);
}
EXPORT_SYMBOL(tifm_queue_work);

int tifm_register_driver(struct tifm_driver *drv)
{
drv->driver.bus = &tifm_bus_type;
Expand All @@ -283,13 +287,25 @@ EXPORT_SYMBOL(tifm_unregister_driver);

static int __init tifm_init(void)
{
int rc = bus_register(&tifm_bus_type);
int rc;

if (!rc) {
rc = class_register(&tifm_adapter_class);
if (rc)
bus_unregister(&tifm_bus_type);
}
workqueue = create_freezeable_workqueue("tifm");
if (!workqueue)
return -ENOMEM;

rc = bus_register(&tifm_bus_type);

if (rc)
goto err_out_wq;

rc = class_register(&tifm_adapter_class);
if (!rc)
return 0;

bus_unregister(&tifm_bus_type);

err_out_wq:
destroy_workqueue(workqueue);

return rc;
}
Expand All @@ -298,6 +314,7 @@ static void __exit tifm_exit(void)
{
class_unregister(&tifm_adapter_class);
bus_unregister(&tifm_bus_type);
destroy_workqueue(workqueue);
}

subsys_initcall(tifm_init);
Expand Down
8 changes: 4 additions & 4 deletions include/linux/tifm.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ struct tifm_adapter {
spinlock_t lock;
unsigned int irq_status;
unsigned int socket_change_set;
wait_queue_head_t change_set_notify;
unsigned int id;
unsigned int num_sockets;
struct completion *finish_me;
struct tifm_dev **sockets;
struct task_struct *media_switcher;
struct work_struct media_switcher;
struct class_device cdev;
struct device *dev;

Expand All @@ -125,7 +125,7 @@ struct tifm_adapter {
struct tifm_adapter *tifm_alloc_adapter(void);
void tifm_free_device(struct device *dev);
void tifm_free_adapter(struct tifm_adapter *fm);
int tifm_add_adapter(struct tifm_adapter *fm, int (*mediathreadfn)(void *data));
int tifm_add_adapter(struct tifm_adapter *fm);
void tifm_remove_adapter(struct tifm_adapter *fm);
struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm);
int tifm_register_driver(struct tifm_driver *drv);
Expand All @@ -135,7 +135,7 @@ int tifm_map_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
int direction);
void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
int direction);

void tifm_queue_work(struct work_struct *work);

static inline void *tifm_get_drvdata(struct tifm_dev *dev)
{
Expand Down

0 comments on commit 3540af8

Please sign in to comment.