From: Mark Brown on
On Wed, Dec 09, 2009 at 12:10:03PM -0500, Alan Stern wrote:
> On Wed, 9 Dec 2009, Mark Brown wrote:

> > Worst case is about a second for both resume and suspend which means two
> > seconds total but it's very hardware dependant.

> A second seems awfully long. What happens if audio isn't being played
> when the suspend occurs? Can't you shorten things with no artifacts in
> that case?

For the affected hardware the problem is basically the same with or
without audio being played. As I said in my reply to Linus this is
delays caused by ramping reference voltages. These delays are
sufficiently long that the reference voltages have to be maintained all
the time so that they don't delay the start of audio streams which means
that having or not having an audio stream at suspend time doesn't affect
the reference voltage ramps since we don't turn them off when not in
use. There is a win from other stuff having been shut off already, but
it's already being exploited.

On suspend the problem is the same as for resume - we need to ramp the
voltages quietly, this time down to zero. We want to make sure they're
actually at zero to ensure that the ramp at resume time starts from a
known hardware state.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
From: Mark Brown on
On Wed, Dec 09, 2009 at 09:57:22AM -0800, Linus Torvalds wrote:
> On Wed, 9 Dec 2009, Mark Brown wrote:

> > The problem comes when you've got audio outputs referenced to something
> > other than ground which used to happen because no negative supplies were
> > available in these systems. To bring these up from cold you need to
> > bring the outputs up to the reference level but if you do that by just
> > turning on the power you get an audible (often loud) noise in the output
> > from the square(ish) waveform that results which users don't find
> > acceptable.

> Ouch. A second still sounds way too long - but whatever.

Yes, I think there's pretty much universal agreement on that :)

Hardware that needs a few hundred miliseconds is much more common at the
minute (and like I say current generation hardware is basically
unaffected), but it's the number I keep in mind when considering how bad
things might be.

> However, it sounds like the nice way to do that isn't by doing it
> synchronously in the suspend/resume code itself, but simply ramping it
> down (and up) from a timer. It would be asynchronous, but not because the
> suspend itself is in any way asynchronous.

We don't actually need a timer for most of this - generally the ramp is
done by charging or discharging a capacitor through a resistor so you
just set it going then wait, possibly in several stages with a little
bit twiddling in the middle to speed things up which could be done off a
timer.

> Done right, it might even result in a nice volume fade of the sound (ie if
> the hw allows for it, stop the actual sound engine late on suspend, and
> start it early on resume, so that sound works _while_ the whole reference
> volume rampdown/up is going on)

The big issue with running off a partially ramped supply is that it can
upset the analogue components - for example, if an amplifier is trying
to handle a signal with an amplitude outside the supply range then it'll
clip. But sometimes that approach does work and it does get used.

For resume we're pretty much taking care of it already by moving the
resume out of the main device resume and using ALSA-specific stuff to
keep audio streams stopped until we're done but for suspend we don't
know the system is going down until the suspend starts and we do want to
make sure we got the analogue into a known poweroff state so that we can
control powerup properly.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
From: Alan Stern on
On Tue, 8 Dec 2009, Linus Torvalds wrote:

> > Wait a second. Are you saying that with code like this:
> >
> > if (x == 1)
> > y = 5;
> >
> > the CPU may write to y before it has finished reading the value of x?

> > And this write is visible to other CPUs, so that if x was initially 0
> > and a second CPU sets x to 1, the second CPU may see y == 5 before it
> > executes the write to x (whatever that may mean)?
>
> Well, yes and no. CPU1 above won't release the '5' until it has confirmed
> the '1' (even if it does so by reading it late). but assuming the other
> CPU also does speculation, then yes, the situation you describe could
> happen. If the other CPU does
>
> z = y;
> x = 1;
>
> then it's certainly possible that 'z' contains 5 at the end (even if both
> x and y started out zero). Because now the read of 'y' on that other CPU
> might be delayed, and the write of 'x' goes ahead, CPU1 sees the 1, and
> commits its write of 5, sp when CPU2 gets the cacheline, z will now
> contain 5.

That could be attributed to reordering on CPU2, so let's take CPU2's
peculiarities out of the picture (initially everything is set to 0):

CPU1 CPU2
---- ----
if (x == 1) z = y;
y = 5; mb();
x = 1;

This gets at the heart of the question: Can a write move up past a
control dependency? Similar questions apply to the two types of data
dependency:

CPU1 CPU2
---- ----
y = x + 4; z = y;
mb();
x = 1;

(Initially p points to x, not y):

CPU1 CPU2
---- ----
*p = 5; z = y;
mb();
p = &y;

Can z end up equal to 5 in any of these examples?

Alan Stern

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
From: Linus Torvalds on


On Wed, 9 Dec 2009, Alan Stern wrote:
>
> That could be attributed to reordering on CPU2, so let's take CPU2's
> peculiarities out of the picture (initially everything is set to 0):
>
> CPU1 CPU2
> ---- ----
> if (x == 1) z = y;
> y = 5; mb();
> x = 1;
>
> This gets at the heart of the question: Can a write move up past a
> control dependency?
> [ .. ]
> Can z end up equal to 5 in any of these examples?

In any _practical_ microarchitecture I know of, the above will never
result in 'z' being 5, even though CPU1 doesn't really have a memory
barrier. But if I read the alpha memory ordering guarantees rigth, then at
least in theory you really can end up with z=5.

Let me write that as five events (with the things in brackets being what
the alpha memory ordering manual calls them):

- A is "read of x returns 1" on CPU1 [ P1:R(x,1) ]
- B is "write of value 5 to y" on CPU1 [ P1:W(y,5) ]
- C is "read of y returns 5" on CPU2 [ P2:R(y,5) ]
- D is "write of value 1 to x" on CPU2 [ P2:W(x,1) ]
- 'MB' is the mb() on CPU2 [ P2:MB ]

(The write of 'z' is irrelevant, we can think of it as a register, the end
result is the same).

And yes, if I read the alpha memory ordering rules correctly, you really
can end up with z=5, although I don't think you will ever find an alpha
_implementation_ that does it.

Why?

The alpha memory ordering literally defines ordering in two ways:

- "location access order". But that is _only_ defined per actual
location, so while 'x' can have a location access order specified by
seeing certain values, there is no "location access order" for two
different memory locations (x and y).

The alpha architecture manual uses "A << B" to say "event A" is before
"event B" when there is a defined ordering.

So in the example above, there is a location access ordering between

P2:W(x,1) << P1:R(x, 1)

and

P2:R(y,5) << P1:W(y,5)

ie you have D << A and B << C.

Good so far, but that doesn't define anything else: there's only
ordering between the pairs (D,A) and (B,C), nothing between them.

- "Processor issue order" for two instruction is _only_ defined by either
(a) memory barriers or (b) accesses to the _same_ locations. The alpha
architecture manual uses "A < B" to say that "event A" is before "event
B" in processor issue order.

So there is a "Processor issue order" on CPU2 due to the memory
barrier: P2:R(y,5) < P2:MB < P2:W(x,1), or put another way C < MB < D:
C < D.

Now, the question is, can we actually get the behaviour of reading 5 on
CPU2 (ie P2:R(y,5)), and that is only possible if we can find an ordering
that satisfies all the constraints. We have

D << A
B << C
C < D

and it seems to be that it is a possible situation: "B C D A"
really does satisfy all the constraints afaik.

So yes, according to the actual alpha architecture memory ordering rules,
you can see '5' from that first read of 'y'. DESPITE having a mb() on
CPU2.

In order to not see 5, you need to also specify "A < B", and the _only_
way to do that processor issue order specification is with a memory
barrier (or if the locations are the same, which they aren't).

"Causality" simply is nowhere in the officially defined alpha memory
ordering. The fact that we test 'x == 1' and conditionally do the write
simply doesn't enter the picture. I suspect you'd have a really hard time
not having causality in practice, but there _are_ things that can break
causality (value prediction etc), so it's not like you'd have to actually
violate physics of reality to do it.

IOW, you could at least in theory implement a CPU that does every
instruction speculatively in parallel, and then validates the end result
afterwards according to the architecture rules. And that CPU would require
the memory barrier on alpha.

(On x86, 'causality' is defined to be part of the memory ordering rules,
so on x86, you _do_ have a 'A < B' relationship. But not on alpha).

Linus
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
From: Rafael J. Wysocki on
On Wednesday 09 December 2009, Alan Stern wrote:
> On Tue, 8 Dec 2009, Rafael J. Wysocki wrote:
>
> > > Well, one difficulty. It arises only because we are contemplating
> > > having the PM core fire up the async tasks, rather than having the
> > > drivers' suspend routines launch them (the way your original proposal
> > > did -- the difficulty does not arise there).
> > >
> > > Suppose A and B are unrelated devices and we need to impose the
> > > off-tree constraint that A suspends after B. With children taking
> > > their parent's lock, the way to prevent A from suspending too soon is
> > > by having B's suspend routine acquire A's lock.
> > >
> > > But B's suspend routine runs entirely in an async task, because that
> > > task is started by the PM core and it does the method call. Hence by
> > > the time B's suspend routine is called, A may already have begun
> > > suspending -- it's too late to take A's lock. To make the locking
> > > work, B would have to acquire A's lock _before_ B's async task starts.
> > > Since the PM core is unaware of the off-tree dependency, there's no
> > > simple way to make it work.
> >
> > Do not set async_suspend for B and instead start your own async thread
> > from its suspend callback. The parent-children synchronization is done by the
> > core anyway (at least I'd do it that way), so the only thing you need to worry
> > about is the extra dependency.
>
> I don't like that because it introduces "artificial" dependencies: It
> makes B depend on all the preceding synchronous suspends, even totally
> unrelated ones. But yes, it would work.

Well, unfortunately, it wouldn't, because (at least in the context of my last
patch) the core would release the rwsems as soon as your suspend had
returned. So you'd have to make your suspend wait for the async thread and
that would make it pointless. So scratch that, it wasn't a good idea at all.

This leaves us with basically two options, where the first one is to use
rwsems in a way that you've proposed (with iterating over children), and the
second one is to use completions. In my opinion rwsems don't give us any
advantage in this case, so I'd very much prefer to use completions.

Rafael
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/