Skip to contentSkip to conversation

Problems with arch/i386/kernel/apm.c

DISCUSSION Jeff Golds 5 participants 6 messages Jun 11, 2001 – Jun 14, 2001

lore
Share & tools
lore

Jeff Golds

author
#0 lore raw

Hi folks,

I've been debugging a problem I've been having with APM. When I initiate an "apm --suspend" command, my Tulip card doesn't work anymore. However, if I then execute "ifconfig eth0 down ; ifconfig eth0 up" then everything is fine again.

I initially thought the problem was on the Tulip driver side, so I instrumented the code and found that the driver was correctly processing incoming and outgoing packets, but it appeared the tx ring was out of sync with the driver.

Since the tulip_suspend, and tulip_resume functions were basically doing the same thing as what "ifconfig eth0 down/up" (WRT to the Tulip driver) I began to look elsewhere. I think I've tracked the problem down to the following code:

static int suspend(void)

{
        int             err;
        struct apm_user *as;
 
	...
        cli();
        err = apm_set_power_state(APM_STATE_SUSPEND);
	...
        send_event(APM_NORMAL_RESUME);
        sti();
	...
        return err;
}                                                                                       

So it seems that drivers are suspended before the cli(), yet they are resumed before the sti(). It seems to me that the sti() should come before apm::send_event(APM_NORMAL_RESUME), and, in fact, if I swap the two, Tulip survives suspend/resume

Please let me know if this is correct, I can provide a simple patch if needed. What I am really desiring to know is if there are any devices that depend on the apm::send_event(APM_NORMAL_RESUME) happening while interrupts are disabled.

-Jeff

Signature · 3 lines
Jeff Golds
Sr. Software Engineer
[email protected]
#1 lore raw
Quoted 4 lines · Jeff Golds

Please let me know if this is correct, I can provide a simple patch if needed. What I am really desiring to know is if there are any devices that depend on the apm::send_event(APM_NORMAL_RESUME) happening while interrupts are disabled.

Good spotting... If any devices depend on what you describe, I would argue that their drivers should handle that not the core apm code...

Signature · 3 lines
Jeff Garzik      | Andre the Giant has a posse.
Building 1024    |
MandrakeSoft     |
#2 lore raw
Quoted 6 lines
Quoted 3 lines

needed. What I am really desiring to know is if there are any devices that depend on the apm::send_event(APM_NORMAL_RESUME) happening while interrupts are disabled.

Good spotting... If any devices depend on what you describe, I would argue that their drivers should handle that not the core apm code...

The drivers can't handle it at the moment. I've been talking to many people about this all hitting this sort of driver problem.

I think the fix is to keep two classes of power management objects and do the following

Call each 'nonirq' suspend function
(aborting if need be)
cli()
Call each irq blocked suspend function
suspend

resume:
call each irq blocked resume function
sti();
call each nonirq resume

That is an easy change set to make and solves a lot of grief

#3 lore raw
Quoted 10 lines · Alan Cox
Quoted 6 lines
Quoted 3 lines

needed. What I am really desiring to know is if there are any devices that depend on the apm::send_event(APM_NORMAL_RESUME) happening while interrupts are disabled.

Good spotting... If any devices depend on what you describe, I would argue that their drivers should handle that not the core apm code...

The drivers can't handle it at the moment. I've been talking to many people about this all hitting this sort of driver problem.

Quoted 8 lines

I think the fix is to keep two classes of power management objects and do the following

Call each 'nonirq' suspend function
(aborting if need be)
cli()
Call each irq blocked suspend function
suspend

It shouldn't be necessary to keep two classes of PM objects; instead walk the device tree twice on suspend.

The first one is an opportunity for the driver to save any device state; a method to notify the driver that it's going to sleep (as some PPC people requested); or to do what it needs to with interrupts enabled.

This also gives the system a graceful way to abort the process should any of the drivers complain that it absolutely cannot suspend (none of the devices will actually be powered off at that point).

We then disable interrupts and walk the tree again, actually shutting off devices. This way, no special cases are made, and no partitioning of the power management objects is needed.

Quoted 4 lines

resume:
call each irq blocked resume function
sti();
call each nonirq resume

Is this really necessary? We should (note _should_) be able to enable interrupts, then walk the device tree to resume everything.

Linus confirmed this assumption, but it may turn out to not be the case. If that is so, then it will be easy enough to do a two stage walk of the tree, like in suspend - one to power on the device and reinitialize it, the next to restore state and continue on once interrupts have been enabled.

-pat

#4 lore raw
Quoted 1 line

Linus confirmed this assumption, but it may turn out to not be the case.

It isnt the case. It's also horrible for debugging if you dont do it two stage because with two stages you can force some restores to be done with irqs off so you can see where the bug is

#5 lore raw
In reply to Jeff Golds

Jeff Golds <[email protected]> writes:
[...]

Quoted 4 lines

Please let me know if this is correct, I can provide a simple patch if needed. What I am really desiring to know is if there are any devices that depend on the apm::send_event(APM_NORMAL_RESUME) happening while interrupts are disabled.

Yes, USB host controllers

Signature · 1 line
	http://ape.n3.net