2003-05-12 21:24:20

by Paul Fulghum

[permalink] [raw]
Subject: PCMCIA 2.5.X sleeping from illegal context

The 2.5.X PCMCIA kernel support seems to have a problem
with drivers/pcmcia/rsrc_mgr.c in function undo_irq().

This function is called from pcmcia_release_irq() in
drivers/pcmcia/cs.c

pcmcia_release_irq() is called by individual drivers
when releasing resources.

When a device gets a CS_EVENT_CARD_REMOVAL event from
cs.c, the device sets a timer to call the release
function defined in the device driver to release resources.
This is the convention used with all PCMCIA drivers I
can see.

The release timer function is running in a context where it
is illegal to call a sleeping function.

undo_irq() has added semaphore calls down(rsrc_sem)/up(rsrc_sem)
in 2.5.X which generates the kernel 'sleeping function called
from illegal context at include/asm/semaphore.h' message.

So, are all the PCMCIA drivers supposed to be changed to not
release resources in the timer context? And if so, what
is the new convention?

Or should the synchronization used in undo_irq() be
changed to something that is legal from a timer context.


Thanks,
Paul

--
Paul Fulghum, [email protected]
Microgate Corporation, http://www.microgate.com



2003-05-12 21:53:47

by David Hinds

[permalink] [raw]
Subject: Re: PCMCIA 2.5.X sleeping from illegal context

On Mon, May 12, 2003 at 04:35:32PM -0500, Paul Fulghum wrote:
>
> So, are all the PCMCIA drivers supposed to be changed to not
> release resources in the timer context? And if so, what
> is the new convention?

yes. The timers should be gotten rid of.

-- Dave

2003-05-12 21:53:03

by Alan

[permalink] [raw]
Subject: Re: PCMCIA 2.5.X sleeping from illegal context

On Llu, 2003-05-12 at 22:35, Paul Fulghum wrote:
> The 2.5.X PCMCIA kernel support seems to have a problem
> with drivers/pcmcia/rsrc_mgr.c in function undo_irq().

Does this still happen with all the patches Russell King posted
that everyone else is ignoring ?

2003-05-12 22:21:32

by Russell King

[permalink] [raw]
Subject: Re: PCMCIA 2.5.X sleeping from illegal context

On Mon, May 12, 2003 at 10:07:13PM +0100, Alan Cox wrote:
> On Llu, 2003-05-12 at 22:35, Paul Fulghum wrote:
> > The 2.5.X PCMCIA kernel support seems to have a problem
> > with drivers/pcmcia/rsrc_mgr.c in function undo_irq().
>
> Does this still happen with all the patches Russell King posted
> that everyone else is ignoring ?

I'm in the process of putting the patch in my outgoing patch queue
for Linus, otherwise we're not going to make any forward progress.

--
Russell King ([email protected]) The developer of ARM Linux
http://www.arm.linux.org.uk/personal/aboutme.html

2003-05-12 22:18:45

by Paul Fulghum

[permalink] [raw]
Subject: Re: PCMCIA 2.5.X sleeping from illegal context

On Mon, 2003-05-12 at 17:06, David Hinds wrote:
> On Mon, May 12, 2003 at 04:35:32PM -0500, Paul Fulghum wrote:
> >
> > So, are all the PCMCIA drivers supposed to be changed to not
> > release resources in the timer context? And if so, what
> > is the new convention?
>
> yes. The timers should be gotten rid of.
>
> -- Dave

Just to be clear, in the device driver
CARD_REMOVAL handler, the release function
should now be called directly instead of
through the timer?

Thanks,
Paul

Paul Fulghum
[email protected]


2003-05-12 22:16:53

by Paul Fulghum

[permalink] [raw]
Subject: Re: PCMCIA 2.5.X sleeping from illegal context

On Mon, 2003-05-12 at 16:07, Alan Cox wrote:
> On Llu, 2003-05-12 at 22:35, Paul Fulghum wrote:
> > The 2.5.X PCMCIA kernel support seems to have a problem
> > with drivers/pcmcia/rsrc_mgr.c in function undo_irq().
>
> Does this still happen with all the patches Russell King posted
> that everyone else is ignoring ?

I don't know, I've been ignoring them :-)

Seriously, are they centralized someplace or
should I scan back and try to extract them
from the lk archive? Do you know about when
they were posted?

Thanks,
Paul

Paul Fulghum
[email protected]


2003-05-12 22:36:09

by Andrew Morton

[permalink] [raw]
Subject: Re: PCMCIA 2.5.X sleeping from illegal context

Paul Fulghum <[email protected]> wrote:
>
> The 2.5.X PCMCIA kernel support seems to have a problem
> with drivers/pcmcia/rsrc_mgr.c in function undo_irq().

The timer handlers need to be converted to use schedule_delayed_work(),
or (more probably) schedule_work().

Alan Cox <[email protected]> wrote:
>
> Does this still happen with all the patches Russell King posted
> that everyone else is ignoring ?

I've had the below in -mm for a couple of weeks. I don't know if
it fixes the down()-in-timer-handler bug?




From: Russell King <[email protected]>

Ok, I think everyone ignored my last email about the updated pcmcia
deadlock patch. I've done a little more work on it since then, so
here it is again. Feedback welcome.

It should apply to bk-curr or 2.5.68 (probably with some offsets
though.)

I've tried all manner of cardctl operations vs plugging and unplugging
cards, as well as module insertion and removal - it seems pretty rock
solid for me.



25-akpm/drivers/pcmcia/cs.c | 721 +++++++++++++++++++----------------
25-akpm/drivers/pcmcia/cs_internal.h | 9
2 files changed, 418 insertions(+), 312 deletions(-)

diff -puN drivers/pcmcia/cs.c~pcmcia-deadlock-fix-2 drivers/pcmcia/cs.c
--- 25/drivers/pcmcia/cs.c~pcmcia-deadlock-fix-2 Tue Apr 29 13:29:35 2003
+++ 25-akpm/drivers/pcmcia/cs.c Tue Apr 29 13:29:35 2003
@@ -302,11 +302,8 @@ static int proc_read_clients(char *buf,

======================================================================*/

-static int setup_socket(socket_info_t *);
-static void shutdown_socket(socket_info_t *);
-static void reset_socket(socket_info_t *);
-static void unreset_socket(socket_info_t *);
-static void parse_events(void *info, u_int events);
+static int pccardd(void *__skt);
+void pcmcia_unregister_socket(struct device *dev);

#define to_class_data(dev) dev->class_data

@@ -317,7 +314,7 @@ int pcmcia_register_socket(struct class_
{
struct pcmcia_socket_class_data *cls_d = class_get_devdata(class_dev);
socket_info_t *s_info;
- unsigned int i, j;
+ unsigned int i, j, ret;

if (!cls_d)
return -EINVAL;
@@ -330,6 +327,7 @@ int pcmcia_register_socket(struct class_
memset(s_info, 0, cls_d->nsock * sizeof(socket_info_t));

cls_d->s_info = s_info;
+ ret = 0;

/* socket initialization */
for (i = 0; i < cls_d->nsock; i++) {
@@ -344,7 +342,7 @@ int pcmcia_register_socket(struct class_
s->erase_busy.next = s->erase_busy.prev = &s->erase_busy;
INIT_LIST_HEAD(&s->cis_cache);
spin_lock_init(&s->lock);
-
+
/* TBD: remove usage of socket_table, use class_for_each_dev instead */
for (j = 0; j < sockets; j++)
if (socket_table[j] == NULL) break;
@@ -353,6 +351,20 @@ int pcmcia_register_socket(struct class_

init_socket(s);
s->ss_entry->inquire_socket(s->sock, &s->cap);
+
+ init_completion(&s->thread_done);
+ init_waitqueue_head(&s->thread_wait);
+ init_MUTEX(&s->skt_sem);
+ spin_lock_init(&s->thread_lock);
+ ret = kernel_thread(pccardd, s, CLONE_KERNEL);
+ if (ret < 0) {
+ pcmcia_unregister_socket(dev);
+ break;
+ }
+
+ wait_for_completion(&s->thread_done);
+ BUG_ON(!s->thread);
+
#ifdef CONFIG_PROC_FS
if (proc_pccard) {
char name[3];
@@ -368,7 +380,7 @@ int pcmcia_register_socket(struct class_
}
#endif
}
- return 0;
+ return ret;
} /* pcmcia_register_socket */


@@ -407,8 +419,12 @@ void pcmcia_unregister_socket(struct cla
remove_proc_entry(name, proc_pccard);
}
#endif
-
- shutdown_socket(s);
+ if (s->thread) {
+ init_completion(&s->thread_done);
+ s->thread = NULL;
+ wake_up(&s->thread_wait);
+ wait_for_completion(&s->thread_done);
+ }
release_cis_mem(s);
while (s->clients) {
client = s->clients;
@@ -450,15 +466,6 @@ static void free_regions(memory_handle_t

static int send_event(socket_info_t *s, event_t event, int priority);

-/*
- * Sleep for n_cs centiseconds (1 cs = 1/100th of a second)
- */
-static void cs_sleep(unsigned int n_cs)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout( (n_cs * HZ + 99) / 100);
-}
-
static void shutdown_socket(socket_info_t *s)
{
client_t **c;
@@ -505,132 +512,6 @@ static void shutdown_socket(socket_info_
free_regions(&s->c_region);
} /* shutdown_socket */

-/*
- * Return zero if we think the card isn't actually present
- */
-static int setup_socket(socket_info_t *s)
-{
- int val, ret;
- int setup_timeout = 100;
-
- /* Wait for "not pending" */
- for (;;) {
- get_socket_status(s, &val);
- if (!(val & SS_PENDING))
- break;
- if (--setup_timeout) {
- cs_sleep(10);
- continue;
- }
- printk(KERN_NOTICE "cs: socket %p voltage interrogation"
- " timed out\n", s);
- ret = 0;
- goto out;
- }
-
- if (val & SS_DETECT) {
- DEBUG(1, "cs: setup_socket(%p): applying power\n", s);
- s->state |= SOCKET_PRESENT;
- s->socket.flags &= SS_DEBOUNCED;
- if (val & SS_3VCARD)
- s->socket.Vcc = s->socket.Vpp = 33;
- else if (!(val & SS_XVCARD))
- s->socket.Vcc = s->socket.Vpp = 50;
- else {
- printk(KERN_NOTICE "cs: socket %p: unsupported "
- "voltage key\n", s);
- s->socket.Vcc = 0;
- }
- if (val & SS_CARDBUS) {
- s->state |= SOCKET_CARDBUS;
-#ifndef CONFIG_CARDBUS
- printk(KERN_NOTICE "cs: unsupported card type detected!\n");
-#endif
- }
- set_socket(s, &s->socket);
- cs_sleep(vcc_settle);
- reset_socket(s);
- ret = 1;
- } else {
- DEBUG(0, "cs: setup_socket(%p): no card!\n", s);
- ret = 0;
- }
-out:
- return ret;
-} /* setup_socket */
-
-/*======================================================================
-
- Reset_socket() and unreset_socket() handle hard resets. Resets
- have several causes: card insertion, a call to reset_socket, or
- recovery from a suspend/resume cycle. Unreset_socket() sends
- a CS event that matches the cause of the reset.
-
-======================================================================*/
-
-static void reset_socket(socket_info_t *s)
-{
- DEBUG(1, "cs: resetting socket %p\n", s);
- s->socket.flags |= SS_OUTPUT_ENA | SS_RESET;
- set_socket(s, &s->socket);
- udelay((long)reset_time);
- s->socket.flags &= ~SS_RESET;
- set_socket(s, &s->socket);
- cs_sleep(unreset_delay);
- unreset_socket(s);
-} /* reset_socket */
-
-#define EVENT_MASK \
-(SOCKET_SETUP_PENDING|SOCKET_SUSPEND|SOCKET_RESET_PENDING)
-
-static void unreset_socket(socket_info_t *s)
-{
- int setup_timeout = unreset_limit;
- int val;
-
- /* Wait for "ready" */
- for (;;) {
- get_socket_status(s, &val);
- if (val & SS_READY)
- break;
- DEBUG(2, "cs: socket %d not ready yet\n", s->sock);
- if (--setup_timeout) {
- cs_sleep(unreset_check);
- continue;
- }
- printk(KERN_NOTICE "cs: socket %p timed out during"
- " reset. Try increasing setup_delay.\n", s);
- s->state &= ~EVENT_MASK;
- return;
- }
-
- DEBUG(1, "cs: reset done on socket %p\n", s);
- if (s->state & SOCKET_SUSPEND) {
- s->state &= ~EVENT_MASK;
- if (verify_cis_cache(s) != 0)
- parse_events(s, SS_DETECT);
- else
- send_event(s, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW);
- } else if (s->state & SOCKET_SETUP_PENDING) {
-#ifdef CONFIG_CARDBUS
- if (s->state & SOCKET_CARDBUS) {
- cb_alloc(s);
- s->state |= SOCKET_CARDBUS_CONFIG;
- }
-#endif
- send_event(s, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
- s->state &= ~SOCKET_SETUP_PENDING;
- } else {
- send_event(s, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW);
- if (s->reset_handle) {
- s->reset_handle->event_callback_args.info = NULL;
- EVENT(s->reset_handle, CS_EVENT_RESET_COMPLETE,
- CS_EVENT_PRI_LOW);
- }
- s->state &= ~EVENT_MASK;
- }
-} /* unreset_socket */
-
/*======================================================================

The central event handler. Send_event() sends an event to all
@@ -661,61 +542,266 @@ static int send_event(socket_info_t *s,
return ret;
} /* send_event */

-static void do_shutdown(socket_info_t *s)
+static void pcmcia_error(socket_info_t *skt, const char *fmt, ...)
{
- client_t *client;
- if (s->state & SOCKET_SHUTDOWN_PENDING)
- return;
- s->state |= SOCKET_SHUTDOWN_PENDING;
- send_event(s, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
- for (client = s->clients; client; client = client->next)
- if (!(client->Attributes & INFO_MASTER_CLIENT))
- client->state |= CLIENT_STALE;
- if (s->state & (SOCKET_SETUP_PENDING|SOCKET_RESET_PENDING)) {
- DEBUG(0, "cs: flushing pending setup\n");
- s->state &= ~EVENT_MASK;
- }
- cs_sleep(shutdown_delay);
- s->state &= ~SOCKET_PRESENT;
- shutdown_socket(s);
+ static char buf[128];
+ va_list ap;
+ int len;
+
+ va_start(ap, fmt);
+ len = vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ buf[len] = '\0';
+
+ printk(KERN_ERR "PCMCIA: socket %p: %s", skt, buf);
+}
+
+#define cs_to_timeout(cs) (((cs) * HZ + 99) / 100)
+
+static void socket_remove_drivers(socket_info_t *skt)
+{
+ client_t *client;
+
+ send_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
+
+ for (client = skt->clients; client; client = client->next)
+ if (!(client->Attributes & INFO_MASTER_CLIENT))
+ client->state |= CLIENT_STALE;
+}
+
+static void socket_shutdown(socket_info_t *skt)
+{
+ socket_remove_drivers(skt);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cs_to_timeout(shutdown_delay));
+ skt->state &= ~SOCKET_PRESENT;
+ shutdown_socket(skt);
+}
+
+static int socket_reset(socket_info_t *skt)
+{
+ int status, i;
+
+ skt->socket.flags |= SS_OUTPUT_ENA | SS_RESET;
+ set_socket(skt, &skt->socket);
+ udelay((long)reset_time);
+
+ skt->socket.flags &= ~SS_RESET;
+ set_socket(skt, &skt->socket);
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cs_to_timeout(unreset_delay));
+ for (i = 0; i < unreset_limit; i++) {
+ get_socket_status(skt, &status);
+
+ if (!(status & SS_DETECT))
+ return CS_NO_CARD;
+
+ if (status & SS_READY)
+ return CS_SUCCESS;
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cs_to_timeout(unreset_check));
+ }
+
+ pcmcia_error(skt, "time out after reset.\n");
+ return CS_GENERAL_FAILURE;
+}
+
+static int socket_setup(socket_info_t *skt, int initial_delay)
+{
+ int status, i;
+
+ get_socket_status(skt, &status);
+ if (!(status & SS_DETECT))
+ return CS_NO_CARD;
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cs_to_timeout(initial_delay));
+
+ for (i = 0; i < 100; i++) {
+ get_socket_status(skt, &status);
+ if (!(status & SS_DETECT))
+ return CS_NO_CARD;
+
+ if (!(status & SS_PENDING))
+ break;
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cs_to_timeout(10));
+ }
+
+ if (status & SS_PENDING) {
+ pcmcia_error(skt, "voltage interrogation timed out.\n");
+ return CS_GENERAL_FAILURE;
+ }
+
+ if (status & SS_CARDBUS) {
+ skt->state |= SOCKET_CARDBUS;
+#ifndef CONFIG_CARDBUS
+ pcmcia_error(skt, "cardbus cards are not supported.\n");
+ return CS_BAD_TYPE;
+#endif
+ }
+
+ /*
+ * Decode the card voltage requirements, and apply power to the card.
+ */
+ if (status & SS_3VCARD)
+ skt->socket.Vcc = skt->socket.Vpp = 33;
+ else if (!(status & SS_XVCARD))
+ skt->socket.Vcc = skt->socket.Vpp = 50;
+ else {
+ pcmcia_error(skt, "unsupported voltage key.\n");
+ return CS_BAD_TYPE;
+ }
+ skt->state |= SOCKET_PRESENT;
+ skt->socket.flags = SS_DEBOUNCED;
+ set_socket(skt, &skt->socket);
+
+ /*
+ * Wait "vcc_settle" for the supply to stabilise.
+ */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cs_to_timeout(vcc_settle));
+
+ return socket_reset(skt);
+}
+
+/*
+ * Handle card insertion. Setup the socket, reset the card,
+ * and then tell the rest of PCMCIA that a card is present.
+ */
+static int socket_insert(socket_info_t *skt)
+{
+ int ret;
+
+ ret = socket_setup(skt, setup_delay);
+ if (ret == CS_SUCCESS) {
+#ifdef CONFIG_CARDBUS
+ if (skt->state & SOCKET_CARDBUS) {
+ cb_alloc(skt);
+ skt->state |= SOCKET_CARDBUS_CONFIG;
+ }
+#endif
+ send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+ skt->socket.flags &= ~SS_DEBOUNCED;
+ } else
+ socket_shutdown(skt);
+
+ return ret;
+}
+
+static int socket_suspend(socket_info_t *skt)
+{
+ if (skt->state & SOCKET_SUSPEND)
+ return CS_IN_USE;
+
+ send_event(skt, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
+ suspend_socket(skt);
+ skt->state |= SOCKET_SUSPEND;
+
+ return CS_SUCCESS;
+}
+
+/*
+ * Resume a socket. If a card is present, verify its CIS against
+ * our cached copy. If they are different, the card has been
+ * replaced, and we need to tell the drivers.
+ */
+static int socket_resume(socket_info_t *skt)
+{
+ int ret;
+
+ if (!(skt->state & SOCKET_SUSPEND))
+ return CS_IN_USE;
+
+ init_socket(skt);
+
+ ret = socket_setup(skt, resume_delay);
+ if (ret == CS_SUCCESS) {
+ /*
+ * FIXME: need a better check here for cardbus cards.
+ */
+ if (verify_cis_cache(skt) != 0) {
+ socket_remove_drivers(skt);
+ destroy_cis_cache(skt);
+ send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+ } else {
+ send_event(skt, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW);
+ }
+ skt->socket.flags &= ~SS_DEBOUNCED;
+ } else
+ socket_shutdown(skt);
+
+ skt->state &= ~SOCKET_SUSPEND;
+
+ return CS_SUCCESS;
+}
+
+static int pccardd(void *__skt)
+{
+ socket_info_t *skt = __skt;
+ DECLARE_WAITQUEUE(wait, current);
+
+ daemonize("pccardd");
+ skt->thread = current;
+ complete(&skt->thread_done);
+
+ add_wait_queue(&skt->thread_wait, &wait);
+ for (;;) {
+ unsigned long flags;
+ unsigned int events;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irqsave(&skt->thread_lock, flags);
+ events = skt->thread_events;
+ skt->thread_events = 0;
+ spin_unlock_irqrestore(&skt->thread_lock, flags);
+
+ if (events) {
+ down(&skt->skt_sem);
+ if (events & SS_DETECT && !(skt->state & SOCKET_SUSPEND)) {
+ int status;
+
+ get_socket_status(skt, &status);
+ if ((skt->state & SOCKET_PRESENT) &&
+ !(status & SS_DETECT))
+ socket_shutdown(skt);
+ if (status & SS_DETECT)
+ socket_insert(skt);
+ }
+ if (events & SS_BATDEAD)
+ send_event(skt, CS_EVENT_BATTERY_DEAD, CS_EVENT_PRI_LOW);
+ if (events & SS_BATWARN)
+ send_event(skt, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);
+ if (events & SS_READY)
+ send_event(skt, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);
+ up(&skt->skt_sem);
+ continue;
+ }
+
+ schedule();
+ if (!skt->thread)
+ break;
+ }
+ remove_wait_queue(&skt->thread_wait, &wait);
+
+ socket_shutdown(skt);
+
+ complete_and_exit(&skt->thread_done, 0);
}

static void parse_events(void *info, u_int events)
{
- socket_info_t *s = info;
- if (events & SS_DETECT) {
- int status;
-
- get_socket_status(s, &status);
- if ((s->state & SOCKET_PRESENT) &&
- (!(s->state & SOCKET_SUSPEND) ||
- !(status & SS_DETECT)))
- do_shutdown(s);
- if (status & SS_DETECT) {
- if (s->state & SOCKET_SETUP_PENDING) {
- DEBUG(1, "cs: delaying pending setup\n");
- return;
- }
- s->state |= SOCKET_SETUP_PENDING;
- if (s->state & SOCKET_SUSPEND)
- cs_sleep(resume_delay);
- else
- cs_sleep(setup_delay);
- s->socket.flags |= SS_DEBOUNCED;
- if (setup_socket(s) == 0)
- s->state &= ~SOCKET_SETUP_PENDING;
- s->socket.flags &= ~SS_DEBOUNCED;
- }
- }
- if (events & SS_BATDEAD)
- send_event(s, CS_EVENT_BATTERY_DEAD, CS_EVENT_PRI_LOW);
- if (events & SS_BATWARN)
- send_event(s, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);
- if (events & SS_READY) {
- if (!(s->state & SOCKET_RESET_PENDING))
- send_event(s, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);
- else DEBUG(1, "cs: ready change during reset\n");
- }
+ socket_info_t *s = info;
+
+ spin_lock(&s->thread_lock);
+ s->thread_events |= events;
+ spin_unlock(&s->thread_lock);
+
+ wake_up(&s->thread_wait);
} /* parse_events */

/*======================================================================
@@ -727,27 +813,18 @@ static void parse_events(void *info, u_i

======================================================================*/

-void pcmcia_suspend_socket (socket_info_t *s)
+void pcmcia_suspend_socket (socket_info_t *skt)
{
- if ((s->state & SOCKET_PRESENT) && !(s->state & SOCKET_SUSPEND)) {
- send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
- suspend_socket(s);
- s->state |= SOCKET_SUSPEND;
- }
+ down(&skt->skt_sem);
+ socket_suspend(skt);
+ up(&skt->skt_sem);
}

-void pcmcia_resume_socket (socket_info_t *s)
+void pcmcia_resume_socket (socket_info_t *skt)
{
- int stat;
-
- /* Do this just to reinitialize the socket */
- init_socket(s);
- get_socket_status(s, &stat);
-
- /* If there was or is a card here, we need to do something
- about it... but parse_events will sort it all out. */
- if ((s->state & SOCKET_PRESENT) || (stat & SS_DETECT))
- parse_events(s, SS_DETECT);
+ down(&skt->skt_sem);
+ socket_resume(skt);
+ up(&skt->skt_sem);
}


@@ -1461,15 +1538,8 @@ int pcmcia_register_client(client_handle

s = socket_table[ns];
if (++s->real_clients == 1) {
- int status;
register_callback(s, &parse_events, s);
- get_socket_status(s, &status);
- if ((status & SS_DETECT) &&
- !(s->state & SOCKET_SETUP_PENDING)) {
- s->state |= SOCKET_SETUP_PENDING;
- if (setup_socket(s) == 0)
- s->state &= ~SOCKET_SETUP_PENDING;
- }
+ parse_events(s, SS_DETECT);
}

*handle = client;
@@ -2022,30 +2092,44 @@ int pcmcia_request_window(client_handle_

int pcmcia_reset_card(client_handle_t handle, client_req_t *req)
{
- int i, ret;
- socket_info_t *s;
+ socket_info_t *skt;
+ int ret;

- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- i = handle->Socket; s = socket_table[i];
- if (!(s->state & SOCKET_PRESENT))
- return CS_NO_CARD;
- if (s->state & SOCKET_RESET_PENDING)
- return CS_IN_USE;
- s->state |= SOCKET_RESET_PENDING;
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ DEBUG(1, "cs: resetting socket %d\n", handle->Socket);
+ skt = SOCKET(handle);
+
+ down(&skt->skt_sem);
+ do {
+ if (!(skt->state & SOCKET_PRESENT)) {
+ ret = CS_NO_CARD;
+ break;
+ }
+ if (skt->state & SOCKET_SUSPEND) {
+ ret = CS_IN_USE;
+ break;
+ }
+ if (skt->state & SOCKET_CARDBUS) {
+ ret = CS_UNSUPPORTED_FUNCTION;
+ break;
+ }

- ret = send_event(s, CS_EVENT_RESET_REQUEST, CS_EVENT_PRI_LOW);
- if (ret != 0) {
- s->state &= ~SOCKET_RESET_PENDING;
- handle->event_callback_args.info = (void *)(u_long)ret;
- EVENT(handle, CS_EVENT_RESET_COMPLETE, CS_EVENT_PRI_LOW);
- } else {
- DEBUG(1, "cs: resetting socket %d\n", i);
- send_event(s, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW);
- s->reset_handle = handle;
- reset_socket(s);
- }
- return CS_SUCCESS;
+ ret = send_event(skt, CS_EVENT_RESET_REQUEST, CS_EVENT_PRI_LOW);
+ if (ret == 0) {
+ send_event(skt, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW);
+ if (socket_reset(skt) == CS_SUCCESS)
+ send_event(skt, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW);
+ }
+
+ handle->event_callback_args.info = (void *)(u_long)ret;
+ EVENT(handle, CS_EVENT_RESET_COMPLETE, CS_EVENT_PRI_LOW);
+
+ ret = CS_SUCCESS;
+ } while (0);
+ up(&skt->skt_sem);
+
+ return ret;
} /* reset_card */

/*======================================================================
@@ -2057,42 +2141,56 @@ int pcmcia_reset_card(client_handle_t ha

int pcmcia_suspend_card(client_handle_t handle, client_req_t *req)
{
- int i;
- socket_info_t *s;
+ socket_info_t *skt;
+ int ret;

- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- i = handle->Socket; s = socket_table[i];
- if (!(s->state & SOCKET_PRESENT))
- return CS_NO_CARD;
- if (s->state & SOCKET_SUSPEND)
- return CS_IN_USE;
-
- DEBUG(1, "cs: suspending socket %d\n", i);
- send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
- suspend_socket(s);
- s->state |= SOCKET_SUSPEND;
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ DEBUG(1, "cs: suspending socket %d\n", handle->Socket);
+ skt = SOCKET(handle);
+
+ down(&skt->skt_sem);
+ do {
+ if (!(skt->state & SOCKET_PRESENT)) {
+ ret = CS_NO_CARD;
+ break;
+ }
+ if (skt->state & SOCKET_CARDBUS) {
+ ret = CS_UNSUPPORTED_FUNCTION;
+ break;
+ }
+ ret = socket_suspend(skt);
+ } while (0);
+ up(&skt->skt_sem);

- return CS_SUCCESS;
+ return ret;
} /* suspend_card */

int pcmcia_resume_card(client_handle_t handle, client_req_t *req)
{
- int i;
- socket_info_t *s;
+ socket_info_t *skt;
+ int ret;

- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- i = handle->Socket; s = socket_table[i];
- if (!(s->state & SOCKET_PRESENT))
- return CS_NO_CARD;
- if (!(s->state & SOCKET_SUSPEND))
- return CS_IN_USE;
-
- DEBUG(1, "cs: waking up socket %d\n", i);
- setup_socket(s);
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ DEBUG(1, "cs: waking up socket %d\n", handle->Socket);
+ skt = SOCKET(handle);
+
+ down(&skt->skt_sem);
+ do {
+ if (!(skt->state & SOCKET_PRESENT)) {
+ ret = CS_NO_CARD;
+ break;
+ }
+ if (skt->state & SOCKET_CARDBUS) {
+ ret = CS_UNSUPPORTED_FUNCTION;
+ break;
+ }
+ ret = socket_resume(skt);
+ } while (0);
+ up(&skt->skt_sem);

- return CS_SUCCESS;
+ return ret;
} /* resume_card */

/*======================================================================
@@ -2103,57 +2201,58 @@ int pcmcia_resume_card(client_handle_t h

int pcmcia_eject_card(client_handle_t handle, client_req_t *req)
{
- int i, ret;
- socket_info_t *s;
- u_long flags;
+ socket_info_t *skt;
+ int ret;

- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- i = handle->Socket; s = socket_table[i];
- if (!(s->state & SOCKET_PRESENT))
- return CS_NO_CARD;
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ DEBUG(1, "cs: user eject request on socket %d\n", handle->Socket);
+ skt = SOCKET(handle);
+
+ down(&skt->skt_sem);
+ do {
+ if (!(skt->state & SOCKET_PRESENT)) {
+ ret = CS_NO_CARD;
+ break;
+ }

- DEBUG(1, "cs: user eject request on socket %d\n", i);
+ ret = send_event(skt, CS_EVENT_EJECTION_REQUEST, CS_EVENT_PRI_LOW);
+ if (ret != 0)
+ break;

- ret = send_event(s, CS_EVENT_EJECTION_REQUEST, CS_EVENT_PRI_LOW);
- if (ret != 0)
- return ret;
+ socket_shutdown(skt);
+ ret = CS_SUCCESS;
+ } while (0);
+ up(&skt->skt_sem);

- spin_lock_irqsave(&s->lock, flags);
- do_shutdown(s);
- spin_unlock_irqrestore(&s->lock, flags);
-
- return CS_SUCCESS;
-
+ return ret;
} /* eject_card */

int pcmcia_insert_card(client_handle_t handle, client_req_t *req)
{
- int i, status;
- socket_info_t *s;
- u_long flags;
-
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- i = handle->Socket; s = socket_table[i];
- if (s->state & SOCKET_PRESENT)
- return CS_IN_USE;
-
- DEBUG(1, "cs: user insert request on socket %d\n", i);
+ socket_info_t *skt;
+ int ret;

- spin_lock_irqsave(&s->lock, flags);
- if (!(s->state & SOCKET_SETUP_PENDING)) {
- s->state |= SOCKET_SETUP_PENDING;
- spin_unlock_irqrestore(&s->lock, flags);
- get_socket_status(s, &status);
- if ((status & SS_DETECT) == 0 || (setup_socket(s) == 0)) {
- s->state &= ~SOCKET_SETUP_PENDING;
- return CS_NO_CARD;
- }
- } else
- spin_unlock_irqrestore(&s->lock, flags);
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ DEBUG(1, "cs: user insert request on socket %d\n", handle->Socket);
+ skt = SOCKET(handle);
+
+ down(&skt->skt_sem);
+ do {
+ if (skt->state & SOCKET_PRESENT) {
+ ret = CS_IN_USE;
+ break;
+ }
+ if (socket_insert(skt) == CS_NO_CARD) {
+ ret = CS_NO_CARD;
+ break;
+ }
+ ret = CS_SUCCESS;
+ } while (0);
+ up(&skt->skt_sem);

- return CS_SUCCESS;
+ return ret;
} /* insert_card */

/*======================================================================
diff -puN drivers/pcmcia/cs_internal.h~pcmcia-deadlock-fix-2 drivers/pcmcia/cs_internal.h
--- 25/drivers/pcmcia/cs_internal.h~pcmcia-deadlock-fix-2 Tue Apr 29 13:29:35 2003
+++ 25-akpm/drivers/pcmcia/cs_internal.h Tue Apr 29 13:29:35 2003
@@ -133,7 +133,6 @@ typedef struct socket_info_t {
u_short lock_count;
client_handle_t clients;
u_int real_clients;
- client_handle_t reset_handle;
pccard_mem_map cis_mem;
u_char *cis_virt;
config_t *config;
@@ -155,6 +154,14 @@ typedef struct socket_info_t {
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc;
#endif
+
+ struct semaphore skt_sem; /* protects socket h/w state */
+
+ struct task_struct *thread;
+ struct completion thread_done;
+ wait_queue_head_t thread_wait;
+ spinlock_t thread_lock; /* protects thread_events */
+ unsigned int thread_events;
} socket_info_t;

/* Flags in config state */

_

2003-05-12 22:38:30

by Russell King

[permalink] [raw]
Subject: Re: PCMCIA 2.5.X sleeping from illegal context

On Mon, May 12, 2003 at 07:36:05AM -0500, Paul Fulghum wrote:
> On Mon, 2003-05-12 at 16:07, Alan Cox wrote:
> > On Llu, 2003-05-12 at 22:35, Paul Fulghum wrote:
> > > The 2.5.X PCMCIA kernel support seems to have a problem
> > > with drivers/pcmcia/rsrc_mgr.c in function undo_irq().
> >
> > Does this still happen with all the patches Russell King posted
> > that everyone else is ignoring ?
>
> I don't know, I've been ignoring them :-)
>
> Seriously, are they centralized someplace or
> should I scan back and try to extract them
> from the lk archive? Do you know about when
> they were posted?

Try this one. Its a slightly updated version from the one I sent earlier.

diff -u /net/flint/usrc/linux-bk-2.5/linux-2.5-pcmcia/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
--- /net/flint/usrc/linux-bk-2.5/linux-2.5-pcmcia/drivers/pcmcia/cs.c Sat Apr 26 23:00:59 2003
+++ linux/drivers/pcmcia/cs.c Sat Apr 26 23:07:24 2003
@@ -302,11 +302,8 @@

======================================================================*/

-static int setup_socket(socket_info_t *);
-static void shutdown_socket(socket_info_t *);
-static void reset_socket(socket_info_t *);
-static void unreset_socket(socket_info_t *);
-static void parse_events(void *info, u_int events);
+static int pccardd(void *__skt);
+void pcmcia_unregister_socket(struct class_device *dev);

#define to_class_data(dev) dev->class_data

@@ -317,7 +314,7 @@
{
struct pcmcia_socket_class_data *cls_d = class_get_devdata(class_dev);
socket_info_t *s_info;
- unsigned int i, j;
+ unsigned int i, j, ret;

if (!cls_d)
return -EINVAL;
@@ -330,6 +327,7 @@
memset(s_info, 0, cls_d->nsock * sizeof(socket_info_t));

cls_d->s_info = s_info;
+ ret = 0;

/* socket initialization */
for (i = 0; i < cls_d->nsock; i++) {
@@ -344,7 +342,7 @@
s->erase_busy.next = s->erase_busy.prev = &s->erase_busy;
INIT_LIST_HEAD(&s->cis_cache);
spin_lock_init(&s->lock);
-
+
/* TBD: remove usage of socket_table, use class_for_each_dev instead */
for (j = 0; j < sockets; j++)
if (socket_table[j] == NULL) break;
@@ -353,6 +351,20 @@

init_socket(s);
s->ss_entry->inquire_socket(s->sock, &s->cap);
+
+ init_completion(&s->thread_done);
+ init_waitqueue_head(&s->thread_wait);
+ init_MUTEX(&s->skt_sem);
+ spin_lock_init(&s->thread_lock);
+ ret = kernel_thread(pccardd, s, CLONE_KERNEL);
+ if (ret < 0) {
+ pcmcia_unregister_socket(class_dev);
+ break;
+ }
+
+ wait_for_completion(&s->thread_done);
+ BUG_ON(!s->thread);
+
#ifdef CONFIG_PROC_FS
if (proc_pccard) {
char name[3];
@@ -368,7 +380,7 @@
}
#endif
}
- return 0;
+ return ret;
} /* pcmcia_register_socket */


@@ -407,8 +419,12 @@
remove_proc_entry(name, proc_pccard);
}
#endif
-
- shutdown_socket(s);
+ if (s->thread) {
+ init_completion(&s->thread_done);
+ s->thread = NULL;
+ wake_up(&s->thread_wait);
+ wait_for_completion(&s->thread_done);
+ }
release_cis_mem(s);
while (s->clients) {
client = s->clients;
@@ -450,15 +466,6 @@

static int send_event(socket_info_t *s, event_t event, int priority);

-/*
- * Sleep for n_cs centiseconds (1 cs = 1/100th of a second)
- */
-static void cs_sleep(unsigned int n_cs)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout( (n_cs * HZ + 99) / 100);
-}
-
static void shutdown_socket(socket_info_t *s)
{
client_t **c;
@@ -505,132 +512,6 @@
free_regions(&s->c_region);
} /* shutdown_socket */

-/*
- * Return zero if we think the card isn't actually present
- */
-static int setup_socket(socket_info_t *s)
-{
- int val, ret;
- int setup_timeout = 100;
-
- /* Wait for "not pending" */
- for (;;) {
- get_socket_status(s, &val);
- if (!(val & SS_PENDING))
- break;
- if (--setup_timeout) {
- cs_sleep(10);
- continue;
- }
- printk(KERN_NOTICE "cs: socket %p voltage interrogation"
- " timed out\n", s);
- ret = 0;
- goto out;
- }
-
- if (val & SS_DETECT) {
- DEBUG(1, "cs: setup_socket(%p): applying power\n", s);
- s->state |= SOCKET_PRESENT;
- s->socket.flags &= SS_DEBOUNCED;
- if (val & SS_3VCARD)
- s->socket.Vcc = s->socket.Vpp = 33;
- else if (!(val & SS_XVCARD))
- s->socket.Vcc = s->socket.Vpp = 50;
- else {
- printk(KERN_NOTICE "cs: socket %p: unsupported "
- "voltage key\n", s);
- s->socket.Vcc = 0;
- }
- if (val & SS_CARDBUS) {
- s->state |= SOCKET_CARDBUS;
-#ifndef CONFIG_CARDBUS
- printk(KERN_NOTICE "cs: unsupported card type detected!\n");
-#endif
- }
- set_socket(s, &s->socket);
- cs_sleep(vcc_settle);
- reset_socket(s);
- ret = 1;
- } else {
- DEBUG(0, "cs: setup_socket(%p): no card!\n", s);
- ret = 0;
- }
-out:
- return ret;
-} /* setup_socket */
-
-/*======================================================================
-
- Reset_socket() and unreset_socket() handle hard resets. Resets
- have several causes: card insertion, a call to reset_socket, or
- recovery from a suspend/resume cycle. Unreset_socket() sends
- a CS event that matches the cause of the reset.
-
-======================================================================*/
-
-static void reset_socket(socket_info_t *s)
-{
- DEBUG(1, "cs: resetting socket %p\n", s);
- s->socket.flags |= SS_OUTPUT_ENA | SS_RESET;
- set_socket(s, &s->socket);
- udelay((long)reset_time);
- s->socket.flags &= ~SS_RESET;
- set_socket(s, &s->socket);
- cs_sleep(unreset_delay);
- unreset_socket(s);
-} /* reset_socket */
-
-#define EVENT_MASK \
-(SOCKET_SETUP_PENDING|SOCKET_SUSPEND|SOCKET_RESET_PENDING)
-
-static void unreset_socket(socket_info_t *s)
-{
- int setup_timeout = unreset_limit;
- int val;
-
- /* Wait for "ready" */
- for (;;) {
- get_socket_status(s, &val);
- if (val & SS_READY)
- break;
- DEBUG(2, "cs: socket %d not ready yet\n", s->sock);
- if (--setup_timeout) {
- cs_sleep(unreset_check);
- continue;
- }
- printk(KERN_NOTICE "cs: socket %p timed out during"
- " reset. Try increasing setup_delay.\n", s);
- s->state &= ~EVENT_MASK;
- return;
- }
-
- DEBUG(1, "cs: reset done on socket %p\n", s);
- if (s->state & SOCKET_SUSPEND) {
- s->state &= ~EVENT_MASK;
- if (verify_cis_cache(s) != 0)
- parse_events(s, SS_DETECT);
- else
- send_event(s, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW);
- } else if (s->state & SOCKET_SETUP_PENDING) {
-#ifdef CONFIG_CARDBUS
- if (s->state & SOCKET_CARDBUS) {
- cb_alloc(s);
- s->state |= SOCKET_CARDBUS_CONFIG;
- }
-#endif
- send_event(s, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
- s->state &= ~SOCKET_SETUP_PENDING;
- } else {
- send_event(s, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW);
- if (s->reset_handle) {
- s->reset_handle->event_callback_args.info = NULL;
- EVENT(s->reset_handle, CS_EVENT_RESET_COMPLETE,
- CS_EVENT_PRI_LOW);
- }
- s->state &= ~EVENT_MASK;
- }
-} /* unreset_socket */
-
/*======================================================================

The central event handler. Send_event() sends an event to all
@@ -661,61 +542,266 @@
return ret;
} /* send_event */

-static void do_shutdown(socket_info_t *s)
+static void pcmcia_error(socket_info_t *skt, const char *fmt, ...)
{
- client_t *client;
- if (s->state & SOCKET_SHUTDOWN_PENDING)
- return;
- s->state |= SOCKET_SHUTDOWN_PENDING;
- send_event(s, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
- for (client = s->clients; client; client = client->next)
- if (!(client->Attributes & INFO_MASTER_CLIENT))
- client->state |= CLIENT_STALE;
- if (s->state & (SOCKET_SETUP_PENDING|SOCKET_RESET_PENDING)) {
- DEBUG(0, "cs: flushing pending setup\n");
- s->state &= ~EVENT_MASK;
- }
- cs_sleep(shutdown_delay);
- s->state &= ~SOCKET_PRESENT;
- shutdown_socket(s);
+ static char buf[128];
+ va_list ap;
+ int len;
+
+ va_start(ap, fmt);
+ len = vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ buf[len] = '\0';
+
+ printk(KERN_ERR "PCMCIA: socket %p: %s", skt, buf);
+}
+
+#define cs_to_timeout(cs) (((cs) * HZ + 99) / 100)
+
+static void socket_remove_drivers(socket_info_t *skt)
+{
+ client_t *client;
+
+ send_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
+
+ for (client = skt->clients; client; client = client->next)
+ if (!(client->Attributes & INFO_MASTER_CLIENT))
+ client->state |= CLIENT_STALE;
+}
+
+static void socket_shutdown(socket_info_t *skt)
+{
+ socket_remove_drivers(skt);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cs_to_timeout(shutdown_delay));
+ skt->state &= ~SOCKET_PRESENT;
+ shutdown_socket(skt);
+}
+
+static int socket_reset(socket_info_t *skt)
+{
+ int status, i;
+
+ skt->socket.flags |= SS_OUTPUT_ENA | SS_RESET;
+ set_socket(skt, &skt->socket);
+ udelay((long)reset_time);
+
+ skt->socket.flags &= ~SS_RESET;
+ set_socket(skt, &skt->socket);
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cs_to_timeout(unreset_delay));
+ for (i = 0; i < unreset_limit; i++) {
+ get_socket_status(skt, &status);
+
+ if (!(status & SS_DETECT))
+ return CS_NO_CARD;
+
+ if (status & SS_READY)
+ return CS_SUCCESS;
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cs_to_timeout(unreset_check));
+ }
+
+ pcmcia_error(skt, "time out after reset.\n");
+ return CS_GENERAL_FAILURE;
+}
+
+static int socket_setup(socket_info_t *skt, int initial_delay)
+{
+ int status, i;
+
+ get_socket_status(skt, &status);
+ if (!(status & SS_DETECT))
+ return CS_NO_CARD;
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cs_to_timeout(initial_delay));
+
+ for (i = 0; i < 100; i++) {
+ get_socket_status(skt, &status);
+ if (!(status & SS_DETECT))
+ return CS_NO_CARD;
+
+ if (!(status & SS_PENDING))
+ break;
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cs_to_timeout(10));
+ }
+
+ if (status & SS_PENDING) {
+ pcmcia_error(skt, "voltage interrogation timed out.\n");
+ return CS_GENERAL_FAILURE;
+ }
+
+ if (status & SS_CARDBUS) {
+ skt->state |= SOCKET_CARDBUS;
+#ifndef CONFIG_CARDBUS
+ pcmcia_error(skt, "cardbus cards are not supported.\n");
+ return CS_BAD_TYPE;
+#endif
+ }
+
+ /*
+ * Decode the card voltage requirements, and apply power to the card.
+ */
+ if (status & SS_3VCARD)
+ skt->socket.Vcc = skt->socket.Vpp = 33;
+ else if (!(status & SS_XVCARD))
+ skt->socket.Vcc = skt->socket.Vpp = 50;
+ else {
+ pcmcia_error(skt, "unsupported voltage key.\n");
+ return CS_BAD_TYPE;
+ }
+ skt->state |= SOCKET_PRESENT;
+ skt->socket.flags = SS_DEBOUNCED;
+ set_socket(skt, &skt->socket);
+
+ /*
+ * Wait "vcc_settle" for the supply to stabilise.
+ */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cs_to_timeout(vcc_settle));
+
+ return socket_reset(skt);
+}
+
+/*
+ * Handle card insertion. Setup the socket, reset the card,
+ * and then tell the rest of PCMCIA that a card is present.
+ */
+static int socket_insert(socket_info_t *skt)
+{
+ int ret;
+
+ ret = socket_setup(skt, setup_delay);
+ if (ret == CS_SUCCESS) {
+#ifdef CONFIG_CARDBUS
+ if (skt->state & SOCKET_CARDBUS) {
+ cb_alloc(skt);
+ skt->state |= SOCKET_CARDBUS_CONFIG;
+ }
+#endif
+ send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+ skt->socket.flags &= ~SS_DEBOUNCED;
+ } else
+ socket_shutdown(skt);
+
+ return ret;
+}
+
+static int socket_suspend(socket_info_t *skt)
+{
+ if (skt->state & SOCKET_SUSPEND)
+ return CS_IN_USE;
+
+ send_event(skt, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
+ suspend_socket(skt);
+ skt->state |= SOCKET_SUSPEND;
+
+ return CS_SUCCESS;
+}
+
+/*
+ * Resume a socket. If a card is present, verify its CIS against
+ * our cached copy. If they are different, the card has been
+ * replaced, and we need to tell the drivers.
+ */
+static int socket_resume(socket_info_t *skt)
+{
+ int ret;
+
+ if (!(skt->state & SOCKET_SUSPEND))
+ return CS_IN_USE;
+
+ init_socket(skt);
+
+ ret = socket_setup(skt, resume_delay);
+ if (ret == CS_SUCCESS) {
+ /*
+ * FIXME: need a better check here for cardbus cards.
+ */
+ if (verify_cis_cache(skt) != 0) {
+ socket_remove_drivers(skt);
+ destroy_cis_cache(skt);
+ send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+ } else {
+ send_event(skt, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW);
+ }
+ skt->socket.flags &= ~SS_DEBOUNCED;
+ } else
+ socket_shutdown(skt);
+
+ skt->state &= ~SOCKET_SUSPEND;
+
+ return CS_SUCCESS;
+}
+
+static int pccardd(void *__skt)
+{
+ socket_info_t *skt = __skt;
+ DECLARE_WAITQUEUE(wait, current);
+
+ daemonize("pccardd");
+ skt->thread = current;
+ complete(&skt->thread_done);
+
+ add_wait_queue(&skt->thread_wait, &wait);
+ for (;;) {
+ unsigned long flags;
+ unsigned int events;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irqsave(&skt->thread_lock, flags);
+ events = skt->thread_events;
+ skt->thread_events = 0;
+ spin_unlock_irqrestore(&skt->thread_lock, flags);
+
+ if (events) {
+ down(&skt->skt_sem);
+ if (events & SS_DETECT && !(skt->state & SOCKET_SUSPEND)) {
+ int status;
+
+ get_socket_status(skt, &status);
+ if ((skt->state & SOCKET_PRESENT) &&
+ !(status & SS_DETECT))
+ socket_shutdown(skt);
+ if (status & SS_DETECT)
+ socket_insert(skt);
+ }
+ if (events & SS_BATDEAD)
+ send_event(skt, CS_EVENT_BATTERY_DEAD, CS_EVENT_PRI_LOW);
+ if (events & SS_BATWARN)
+ send_event(skt, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);
+ if (events & SS_READY)
+ send_event(skt, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);
+ up(&skt->skt_sem);
+ continue;
+ }
+
+ schedule();
+ if (!skt->thread)
+ break;
+ }
+ remove_wait_queue(&skt->thread_wait, &wait);
+
+ socket_shutdown(skt);
+
+ complete_and_exit(&skt->thread_done, 0);
}

static void parse_events(void *info, u_int events)
{
- socket_info_t *s = info;
- if (events & SS_DETECT) {
- int status;
-
- get_socket_status(s, &status);
- if ((s->state & SOCKET_PRESENT) &&
- (!(s->state & SOCKET_SUSPEND) ||
- !(status & SS_DETECT)))
- do_shutdown(s);
- if (status & SS_DETECT) {
- if (s->state & SOCKET_SETUP_PENDING) {
- DEBUG(1, "cs: delaying pending setup\n");
- return;
- }
- s->state |= SOCKET_SETUP_PENDING;
- if (s->state & SOCKET_SUSPEND)
- cs_sleep(resume_delay);
- else
- cs_sleep(setup_delay);
- s->socket.flags |= SS_DEBOUNCED;
- if (setup_socket(s) == 0)
- s->state &= ~SOCKET_SETUP_PENDING;
- s->socket.flags &= ~SS_DEBOUNCED;
- }
- }
- if (events & SS_BATDEAD)
- send_event(s, CS_EVENT_BATTERY_DEAD, CS_EVENT_PRI_LOW);
- if (events & SS_BATWARN)
- send_event(s, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);
- if (events & SS_READY) {
- if (!(s->state & SOCKET_RESET_PENDING))
- send_event(s, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);
- else DEBUG(1, "cs: ready change during reset\n");
- }
+ socket_info_t *s = info;
+
+ spin_lock(&s->thread_lock);
+ s->thread_events |= events;
+ spin_unlock(&s->thread_lock);
+
+ wake_up(&s->thread_wait);
} /* parse_events */

/*======================================================================
@@ -727,27 +813,18 @@

======================================================================*/

-void pcmcia_suspend_socket (socket_info_t *s)
+void pcmcia_suspend_socket (socket_info_t *skt)
{
- if ((s->state & SOCKET_PRESENT) && !(s->state & SOCKET_SUSPEND)) {
- send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
- suspend_socket(s);
- s->state |= SOCKET_SUSPEND;
- }
+ down(&skt->skt_sem);
+ socket_suspend(skt);
+ up(&skt->skt_sem);
}

-void pcmcia_resume_socket (socket_info_t *s)
+void pcmcia_resume_socket (socket_info_t *skt)
{
- int stat;
-
- /* Do this just to reinitialize the socket */
- init_socket(s);
- get_socket_status(s, &stat);
-
- /* If there was or is a card here, we need to do something
- about it... but parse_events will sort it all out. */
- if ((s->state & SOCKET_PRESENT) || (stat & SS_DETECT))
- parse_events(s, SS_DETECT);
+ down(&skt->skt_sem);
+ socket_resume(skt);
+ up(&skt->skt_sem);
}


@@ -1461,15 +1538,8 @@

s = socket_table[ns];
if (++s->real_clients == 1) {
- int status;
register_callback(s, &parse_events, s);
- get_socket_status(s, &status);
- if ((status & SS_DETECT) &&
- !(s->state & SOCKET_SETUP_PENDING)) {
- s->state |= SOCKET_SETUP_PENDING;
- if (setup_socket(s) == 0)
- s->state &= ~SOCKET_SETUP_PENDING;
- }
+ parse_events(s, SS_DETECT);
}

*handle = client;
@@ -2022,30 +2092,44 @@

int pcmcia_reset_card(client_handle_t handle, client_req_t *req)
{
- int i, ret;
- socket_info_t *s;
+ socket_info_t *skt;
+ int ret;

- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- i = handle->Socket; s = socket_table[i];
- if (!(s->state & SOCKET_PRESENT))
- return CS_NO_CARD;
- if (s->state & SOCKET_RESET_PENDING)
- return CS_IN_USE;
- s->state |= SOCKET_RESET_PENDING;
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ DEBUG(1, "cs: resetting socket %d\n", handle->Socket);
+ skt = SOCKET(handle);
+
+ down(&skt->skt_sem);
+ do {
+ if (!(skt->state & SOCKET_PRESENT)) {
+ ret = CS_NO_CARD;
+ break;
+ }
+ if (skt->state & SOCKET_SUSPEND) {
+ ret = CS_IN_USE;
+ break;
+ }
+ if (skt->state & SOCKET_CARDBUS) {
+ ret = CS_UNSUPPORTED_FUNCTION;
+ break;
+ }

- ret = send_event(s, CS_EVENT_RESET_REQUEST, CS_EVENT_PRI_LOW);
- if (ret != 0) {
- s->state &= ~SOCKET_RESET_PENDING;
- handle->event_callback_args.info = (void *)(u_long)ret;
- EVENT(handle, CS_EVENT_RESET_COMPLETE, CS_EVENT_PRI_LOW);
- } else {
- DEBUG(1, "cs: resetting socket %d\n", i);
- send_event(s, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW);
- s->reset_handle = handle;
- reset_socket(s);
- }
- return CS_SUCCESS;
+ ret = send_event(skt, CS_EVENT_RESET_REQUEST, CS_EVENT_PRI_LOW);
+ if (ret == 0) {
+ send_event(skt, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW);
+ if (socket_reset(skt) == CS_SUCCESS)
+ send_event(skt, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW);
+ }
+
+ handle->event_callback_args.info = (void *)(u_long)ret;
+ EVENT(handle, CS_EVENT_RESET_COMPLETE, CS_EVENT_PRI_LOW);
+
+ ret = CS_SUCCESS;
+ } while (0);
+ up(&skt->skt_sem);
+
+ return ret;
} /* reset_card */

/*======================================================================
@@ -2057,42 +2141,56 @@

int pcmcia_suspend_card(client_handle_t handle, client_req_t *req)
{
- int i;
- socket_info_t *s;
+ socket_info_t *skt;
+ int ret;

- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- i = handle->Socket; s = socket_table[i];
- if (!(s->state & SOCKET_PRESENT))
- return CS_NO_CARD;
- if (s->state & SOCKET_SUSPEND)
- return CS_IN_USE;
-
- DEBUG(1, "cs: suspending socket %d\n", i);
- send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
- suspend_socket(s);
- s->state |= SOCKET_SUSPEND;
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ DEBUG(1, "cs: suspending socket %d\n", handle->Socket);
+ skt = SOCKET(handle);
+
+ down(&skt->skt_sem);
+ do {
+ if (!(skt->state & SOCKET_PRESENT)) {
+ ret = CS_NO_CARD;
+ break;
+ }
+ if (skt->state & SOCKET_CARDBUS) {
+ ret = CS_UNSUPPORTED_FUNCTION;
+ break;
+ }
+ ret = socket_suspend(skt);
+ } while (0);
+ up(&skt->skt_sem);

- return CS_SUCCESS;
+ return ret;
} /* suspend_card */

int pcmcia_resume_card(client_handle_t handle, client_req_t *req)
{
- int i;
- socket_info_t *s;
+ socket_info_t *skt;
+ int ret;

- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- i = handle->Socket; s = socket_table[i];
- if (!(s->state & SOCKET_PRESENT))
- return CS_NO_CARD;
- if (!(s->state & SOCKET_SUSPEND))
- return CS_IN_USE;
-
- DEBUG(1, "cs: waking up socket %d\n", i);
- setup_socket(s);
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ DEBUG(1, "cs: waking up socket %d\n", handle->Socket);
+ skt = SOCKET(handle);
+
+ down(&skt->skt_sem);
+ do {
+ if (!(skt->state & SOCKET_PRESENT)) {
+ ret = CS_NO_CARD;
+ break;
+ }
+ if (skt->state & SOCKET_CARDBUS) {
+ ret = CS_UNSUPPORTED_FUNCTION;
+ break;
+ }
+ ret = socket_resume(skt);
+ } while (0);
+ up(&skt->skt_sem);

- return CS_SUCCESS;
+ return ret;
} /* resume_card */

/*======================================================================
@@ -2103,57 +2201,58 @@

int pcmcia_eject_card(client_handle_t handle, client_req_t *req)
{
- int i, ret;
- socket_info_t *s;
- u_long flags;
+ socket_info_t *skt;
+ int ret;

- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- i = handle->Socket; s = socket_table[i];
- if (!(s->state & SOCKET_PRESENT))
- return CS_NO_CARD;
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ DEBUG(1, "cs: user eject request on socket %d\n", handle->Socket);
+ skt = SOCKET(handle);
+
+ down(&skt->skt_sem);
+ do {
+ if (!(skt->state & SOCKET_PRESENT)) {
+ ret = CS_NO_CARD;
+ break;
+ }

- DEBUG(1, "cs: user eject request on socket %d\n", i);
+ ret = send_event(skt, CS_EVENT_EJECTION_REQUEST, CS_EVENT_PRI_LOW);
+ if (ret != 0)
+ break;

- ret = send_event(s, CS_EVENT_EJECTION_REQUEST, CS_EVENT_PRI_LOW);
- if (ret != 0)
- return ret;
+ socket_shutdown(skt);
+ ret = CS_SUCCESS;
+ } while (0);
+ up(&skt->skt_sem);

- spin_lock_irqsave(&s->lock, flags);
- do_shutdown(s);
- spin_unlock_irqrestore(&s->lock, flags);
-
- return CS_SUCCESS;
-
+ return ret;
} /* eject_card */

int pcmcia_insert_card(client_handle_t handle, client_req_t *req)
{
- int i, status;
- socket_info_t *s;
- u_long flags;
-
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- i = handle->Socket; s = socket_table[i];
- if (s->state & SOCKET_PRESENT)
- return CS_IN_USE;
-
- DEBUG(1, "cs: user insert request on socket %d\n", i);
+ socket_info_t *skt;
+ int ret;

- spin_lock_irqsave(&s->lock, flags);
- if (!(s->state & SOCKET_SETUP_PENDING)) {
- s->state |= SOCKET_SETUP_PENDING;
- spin_unlock_irqrestore(&s->lock, flags);
- get_socket_status(s, &status);
- if ((status & SS_DETECT) == 0 || (setup_socket(s) == 0)) {
- s->state &= ~SOCKET_SETUP_PENDING;
- return CS_NO_CARD;
- }
- } else
- spin_unlock_irqrestore(&s->lock, flags);
+ if (CHECK_HANDLE(handle))
+ return CS_BAD_HANDLE;
+ DEBUG(1, "cs: user insert request on socket %d\n", handle->Socket);
+ skt = SOCKET(handle);
+
+ down(&skt->skt_sem);
+ do {
+ if (skt->state & SOCKET_PRESENT) {
+ ret = CS_IN_USE;
+ break;
+ }
+ if (socket_insert(skt) == CS_NO_CARD) {
+ ret = CS_NO_CARD;
+ break;
+ }
+ ret = CS_SUCCESS;
+ } while (0);
+ up(&skt->skt_sem);

- return CS_SUCCESS;
+ return ret;
} /* insert_card */

/*======================================================================
diff -u /net/flint/usrc/linux-bk-2.5/linux-2.5-pcmcia/drivers/pcmcia/cs_internal.h linux/drivers/pcmcia/cs_internal.h
--- /net/flint/usrc/linux-bk-2.5/linux-2.5-pcmcia/drivers/pcmcia/cs_internal.h Sat Apr 26 23:01:03 2003
+++ linux/drivers/pcmcia/cs_internal.h Sat Apr 26 21:34:59 2003
@@ -133,7 +133,6 @@
u_short lock_count;
client_handle_t clients;
u_int real_clients;
- client_handle_t reset_handle;
pccard_mem_map cis_mem;
u_char *cis_virt;
config_t *config;
@@ -155,6 +154,14 @@
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc;
#endif
+
+ struct semaphore skt_sem; /* protects socket h/w state */
+
+ struct task_struct *thread;
+ struct completion thread_done;
+ wait_queue_head_t thread_wait;
+ spinlock_t thread_lock; /* protects thread_events */
+ unsigned int thread_events;
} socket_info_t;

/* Flags in config state */

--
Russell King ([email protected]) The developer of ARM Linux
http://www.arm.linux.org.uk/personal/aboutme.html

2003-05-12 22:59:12

by Felipe Alfaro Solana

[permalink] [raw]
Subject: Re: PCMCIA 2.5.X sleeping from illegal context

On Mon, 2003-05-12 at 23:07, Alan Cox wrote:
> On Llu, 2003-05-12 at 22:35, Paul Fulghum wrote:
> > The 2.5.X PCMCIA kernel support seems to have a problem
> > with drivers/pcmcia/rsrc_mgr.c in function undo_irq().
>
> Does this still happen with all the patches Russell King posted
> that everyone else is ignoring ?

Not everybody is ignoring them ;-)

2003-05-12 22:57:48

by David Hinds

[permalink] [raw]
Subject: Re: PCMCIA 2.5.X sleeping from illegal context

On Mon, May 12, 2003 at 03:44:16PM -0700, Andrew Morton wrote:
> Paul Fulghum <[email protected]> wrote:
> >
> > The 2.5.X PCMCIA kernel support seems to have a problem
> > with drivers/pcmcia/rsrc_mgr.c in function undo_irq().
>
> The timer handlers need to be converted to use schedule_delayed_work(),
> or (more probably) schedule_work().

I don't think the timers need to be scheduled at all; the timer code
should just be executed in-line where the old timers were scheduled.

-- Dave

2003-05-12 23:04:18

by Felipe Alfaro Solana

[permalink] [raw]
Subject: Re: PCMCIA 2.5.X sleeping from illegal context

On Tue, 2003-05-13 at 00:31, Russell King wrote:
> > Does this still happen with all the patches Russell King posted
> > that everyone else is ignoring ?
>
> I'm in the process of putting the patch in my outgoing patch queue
> for Linus, otherwise we're not going to make any forward progress.

Well, your patches do work pretty well for me... I've been playing
extensively with PCMCIA today, mainly with my 3Com CardBus NIC which has
really strange TX slowdown problems, by plugging and unplugging it over
and over again, loading and unloading the 3c59x.ko module and so on. So
at least, we're making some progress.
--
Please AVOID sending me WORD, EXCEL or POWERPOINT attachments.
See http://www.fsf.org/philosophy/no-word-attachments.html
Linux Registered User #287198

2003-05-12 23:20:56

by Richard B. Johnson

[permalink] [raw]
Subject: Re: PCMCIA 2.5.X sleeping from illegal context

On Mon, 13 May 2003, Felipe Alfaro Solana wrote:

> On Tue, 2003-05-13 at 00:31, Russell King wrote:
> > > Does this still happen with all the patches Russell King posted
> > > that everyone else is ignoring ?
> >
> > I'm in the process of putting the patch in my outgoing patch queue
> > for Linus, otherwise we're not going to make any forward progress.
>
> Well, your patches do work pretty well for me... I've been playing
> extensively with PCMCIA today, mainly with my 3Com CardBus NIC which has
> really strange TX slowdown problems, by plugging and unplugging it over
> and over again, loading and unloading the 3c59x.ko module and so on. So
> at least, we're making some progress.


Could somebody please change the error message? Although everybody
seems to want to be a lawyer, even lawyers don't make law. Certainly
Software Engineers don't. The correct word is 'invalid', not 'illegal'.
Yes, I know there is a 30-year history of the use of that word in
Unix, but it's wrong. Only governments make law.


Cheers,
Dick Johnson
Penguin : Linux version 2.4.20 on an i686 machine (797.90 BogoMips).
Why is the government concerned about the lunatic fringe? Think about it.

2003-05-12 23:37:50

by Paul Fulghum

[permalink] [raw]
Subject: Re: PCMCIA 2.5.X sleeping from illegal context

On Mon, 2003-05-12 at 18:36, Richard B. Johnson wrote:

> The correct word is 'invalid', not 'illegal'.
> Yes, I know there is a 30-year history of the use of that word in
> Unix, but it's wrong. Only governments make law.

And in the US, large campaign contributors. *rimshot*

Paul Fulghum
[email protected]



2003-05-12 23:55:55

by Thomas Molina

[permalink] [raw]
Subject: Re: PCMCIA 2.5.X sleeping from illegal context

I'm back to testing with 2.5 and I am not having any issues with PCMCIA in
2.5.69-bk. I'm not using any additional patches. System is Presario
12XL325 with RedHat 8.0. It has a Linksys PCMCIA card using the tulip
driver.

On 13 May 2003, Felipe Alfaro Solana wrote:

> On Tue, 2003-05-13 at 00:31, Russell King wrote:
> > > Does this still happen with all the patches Russell King posted
> > > that everyone else is ignoring ?
> >
> > I'm in the process of putting the patch in my outgoing patch queue
> > for Linus, otherwise we're not going to make any forward progress.
>
> Well, your patches do work pretty well for me... I've been playing
> extensively with PCMCIA today, mainly with my 3Com CardBus NIC which has
> really strange TX slowdown problems, by plugging and unplugging it over
> and over again, loading and unloading the 3c59x.ko module and so on. So
> at least, we're making some progress.
>

2003-05-13 00:23:39

by Felipe Alfaro Solana

[permalink] [raw]
Subject: Re: PCMCIA 2.5.X sleeping from illegal context

On Tue, 2003-05-13 at 04:07, Thomas Molina wrote:
> I'm back to testing with 2.5 and I am not having any issues with PCMCIA in
> 2.5.69-bk. I'm not using any additional patches. System is Presario
> 12XL325 with RedHat 8.0. It has a Linksys PCMCIA card using the tulip
> driver.

You'd better try with an -mm kernel. Vanilla and -bk kernels don't still
have Russell latest PCMCIA/CardBus patches.
--
Please AVOID sending me WORD, EXCEL or POWERPOINT attachments.
See http://www.fsf.org/philosophy/no-word-attachments.html
Linux Registered User #287198

2003-05-13 14:23:36

by Alan

[permalink] [raw]
Subject: Re: PCMCIA 2.5.X sleeping from illegal context

On Maw, 2003-05-13 at 00:36, Richard B. Johnson wrote:
> Could somebody please change the error message? Although everybody
> seems to want to be a lawyer, even lawyers don't make law. Certainly
> Software Engineers don't. The correct word is 'invalid', not 'illegal'.
> Yes, I know there is a 30-year history of the use of that word in
> Unix, but it's wrong. Only governments make law.

Much to my suprise you are right on this. The reference dictionary is
quite explicit that "illegal" means prohibited by law. Since users will
eventually see this message it perhaps does make sense to fix it

2003-05-13 15:11:49

by Paul Fulghum

[permalink] [raw]
Subject: Re: PCMCIA 2.5.X sleeping from illegal context

On Mon, 2003-05-12 at 17:48, Russell King wrote:
> On Mon, May 12, 2003 at 07:36:05AM -0500, Paul Fulghum wrote:
> > On Mon, 2003-05-12 at 16:07, Alan Cox wrote:
> > > On Llu, 2003-05-12 at 22:35, Paul Fulghum wrote:
> > > > The 2.5.X PCMCIA kernel support seems to have a problem
> > > > with drivers/pcmcia/rsrc_mgr.c in function undo_irq().
> > >
> > > Does this still happen with all the patches Russell King posted
> > > that everyone else is ignoring ?
> >
> > I don't know, I've been ignoring them :-)
> >
> > Seriously, are they centralized someplace or
> > should I scan back and try to extract them
> > from the lk archive? Do you know about when
> > they were posted?
>
> Try this one. Its a slightly updated version from the one I sent earlier.

I tested this patch, and it works.
But I was not seeing any problems before the patch,
other than the 'sleeping in illegal context message'

There seems to be agreement that the cause of the
message is that individual PCMCIA drivers need to be
modified to call the release function directly
instead of from a timer context.

I modified my synclink_cs driver to do this and it
works and eliminates the error message.

Which brings up a question:
The include/pcmcia/ds.h file defines the dev_link_t
structure that contains the release timer_list member.

Should I continue to initialize this member in
my driver or will this member be eliminated requiring
that all references to this member be removed from
the individual PCMCIA drivers?

--
Paul Fulghum, [email protected]
Microgate Corporation, http://www.microgate.com


2003-05-13 15:47:42

by David Hinds

[permalink] [raw]
Subject: Re: PCMCIA 2.5.X sleeping from illegal context

On Tue, May 13, 2003 at 10:23:05AM -0500, Paul Fulghum wrote:
>
> Which brings up a question:
> The include/pcmcia/ds.h file defines the dev_link_t
> structure that contains the release timer_list member.
>
> Should I continue to initialize this member in
> my driver or will this member be eliminated requiring
> that all references to this member be removed from
> the individual PCMCIA drivers?

You shouldn't need to initialize it in your driver, since you've
eliminated the actual usage of the timer.

-- Dave

2003-05-13 23:25:04

by Andrew Morton

[permalink] [raw]
Subject: Re: PCMCIA 2.5.X sleeping from illegal context

Alan Cox <[email protected]> wrote:
>
> On Maw, 2003-05-13 at 00:36, Richard B. Johnson wrote:
> > Could somebody please change the error message? Although everybody
> > seems to want to be a lawyer, even lawyers don't make law. Certainly
> > Software Engineers don't. The correct word is 'invalid', not 'illegal'.
> > Yes, I know there is a 30-year history of the use of that word in
> > Unix, but it's wrong. Only governments make law.
>
> Much to my suprise you are right on this. The reference dictionary is
> quite explicit that "illegal" means prohibited by law. Since users will
> eventually see this message it perhaps does make sense to fix it
>


diff -puN kernel/sched.c~might-sleep-fix kernel/sched.c
--- 25/kernel/sched.c~might-sleep-fix Tue May 13 16:32:18 2003
+++ 25-akpm/kernel/sched.c Tue May 13 16:32:46 2003
@@ -2842,8 +2842,8 @@ void __might_sleep(char *file, int line)
if (time_before(jiffies, prev_jiffy + HZ))
return;
prev_jiffy = jiffies;
- printk(KERN_ERR "Debug: sleeping function called from illegal"
- " context at %s:%d\n", file, line);
+ printk(KERN_ERR "Debug: sleeping in immoral context "
+ "at %s:%d\n", file, line);
dump_stack();
}
#endif

_

Subject: Re: PCMCIA 2.5.X sleeping from illegal context

Andrew Morton <[email protected]> writes:

>diff -puN kernel/sched.c~might-sleep-fix kernel/sched.c
>--- 25/kernel/sched.c~might-sleep-fix Tue May 13 16:32:18 2003
>+++ 25-akpm/kernel/sched.c Tue May 13 16:32:46 2003
>@@ -2842,8 +2842,8 @@ void __might_sleep(char *file, int line)
> if (time_before(jiffies, prev_jiffy + HZ))
> return;
> prev_jiffy = jiffies;
>- printk(KERN_ERR "Debug: sleeping function called from illegal"
>- " context at %s:%d\n", file, line);
>+ printk(KERN_ERR "Debug: sleeping in immoral context "
>+ "at %s:%d\n", file, line);

We could change "in" to "with" to get an X rating for the kernel error
messages. ;-)

SCNR
Henning


--
Dipl.-Inf. (Univ.) Henning P. Schmiedehausen INTERMETA GmbH
[email protected] +49 9131 50 654 0 http://www.intermeta.de/

Java, perl, Solaris, Linux, xSP Consulting, Web Services
freelance consultant -- Jakarta Turbine Development -- hero for hire