Commit 18e4786e authored by Dominik Brodowski's avatar Dominik Brodowski Committed by Russell King

[PCMCIA] Fix "Removing wireless card triggers might_sleep warnings."

Bug 516.

Use schedule_delayed_work instead of a timer should fix this. Thanks
to Andrew Morton and Russell King.

(Added flush_scheduled_work() to ensure our delayed work completes
before we free the pcmcia_bus_socket structure. --rmk)
parent 4681ce68
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/workqueue.h>
#include <pcmcia/version.h> #include <pcmcia/version.h>
#include <pcmcia/cs_types.h> #include <pcmcia/cs_types.h>
...@@ -103,7 +104,7 @@ struct pcmcia_bus_socket { ...@@ -103,7 +104,7 @@ struct pcmcia_bus_socket {
user_info_t *user; user_info_t *user;
int req_pending, req_result; int req_pending, req_result;
wait_queue_head_t queue, request; wait_queue_head_t queue, request;
struct timer_list removal; struct work_struct removal;
socket_bind_t *bind; socket_bind_t *bind;
struct device *socket_dev; struct device *socket_dev;
struct list_head socket_list; struct list_head socket_list;
...@@ -299,9 +300,9 @@ static int handle_request(struct pcmcia_bus_socket *s, event_t event) ...@@ -299,9 +300,9 @@ static int handle_request(struct pcmcia_bus_socket *s, event_t event)
return CS_SUCCESS; return CS_SUCCESS;
} }
static void handle_removal(u_long sn) static void handle_removal(void *data)
{ {
struct pcmcia_bus_socket *s = get_socket_info_by_nr(sn); struct pcmcia_bus_socket *s = data;
handle_event(s, CS_EVENT_CARD_REMOVAL); handle_event(s, CS_EVENT_CARD_REMOVAL);
s->state &= ~SOCKET_REMOVAL_PENDING; s->state &= ~SOCKET_REMOVAL_PENDING;
} }
...@@ -326,10 +327,8 @@ static int ds_event(event_t event, int priority, ...@@ -326,10 +327,8 @@ static int ds_event(event_t event, int priority,
case CS_EVENT_CARD_REMOVAL: case CS_EVENT_CARD_REMOVAL:
s->state &= ~SOCKET_PRESENT; s->state &= ~SOCKET_PRESENT;
if (!(s->state & SOCKET_REMOVAL_PENDING)) { if (!(s->state & SOCKET_REMOVAL_PENDING)) {
s->state |= SOCKET_REMOVAL_PENDING; s->state |= SOCKET_REMOVAL_PENDING;
init_timer(&s->removal); schedule_delayed_work(&s->removal, HZ/10);
s->removal.expires = jiffies + HZ/10;
add_timer(&s->removal);
} }
break; break;
...@@ -922,9 +921,7 @@ static int __devinit pcmcia_bus_add_socket(struct device *dev, unsigned int sock ...@@ -922,9 +921,7 @@ static int __devinit pcmcia_bus_add_socket(struct device *dev, unsigned int sock
/* initialize data */ /* initialize data */
s->socket_dev = dev; s->socket_dev = dev;
s->removal.data = s->socket_no; INIT_WORK(&s->removal, handle_removal, s);
s->removal.function = &handle_removal;
init_timer(&s->removal);
/* Set up hotline to Card Services */ /* Set up hotline to Card Services */
client_reg.dev_info = bind.dev_info = &dev_info; client_reg.dev_info = bind.dev_info = &dev_info;
...@@ -986,6 +983,8 @@ static int __devexit pcmcia_bus_remove_socket_dev(struct device *dev) ...@@ -986,6 +983,8 @@ static int __devexit pcmcia_bus_remove_socket_dev(struct device *dev)
if (!cls_d) if (!cls_d)
return -ENODEV; return -ENODEV;
flush_scheduled_work();
down_write(&bus_socket_list_rwsem); down_write(&bus_socket_list_rwsem);
list_for_each_safe(list_loop, tmp_storage, &bus_socket_list) { list_for_each_safe(list_loop, tmp_storage, &bus_socket_list) {
struct pcmcia_bus_socket *bus_sock = container_of(list_loop, struct pcmcia_bus_socket, socket_list); struct pcmcia_bus_socket *bus_sock = container_of(list_loop, struct pcmcia_bus_socket, socket_list);
......
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