|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH 2/2] x86/vPIT: account for "counter stopped" time
On Tue, May 30, 2023 at 05:30:40PM +0200, Jan Beulich wrote:
> For an approach like that used in "x86: detect PIT aliasing on ports
> other than 0x4[0-3]" [1] to work, channel 2 may not (appear to) continue
> counting when "gate" is low. Record the time when "gate" goes low, and
> adjust pit_get_{count,out}() accordingly. Additionally for most of the
> modes a rising edge of "gate" doesn't mean just "resume counting", but
> "initiate counting", i.e. specifically the reloading of the counter with
> its init value.
>
> No special handling for state save/load: See the comment near the end of
> pit_load().
>
> [1] https://lists.xen.org/archives/html/xen-devel/2023-05/msg00898.html
>
> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
> ---
> TBD: "gate" can only ever be low for chan2 (with "x86/vPIT: check/bound
> values loaded from state save record" [2] in place), so in
> principle we could get away without a new pair of arrays, but just
> two individual fields. At the expense of more special casing in
> code.
Hm, I guess we could rename to pit_set_gate_ch2 and remove the ch
parameter. That would be OK for me.
> TBD: Should we deal with other aspects of "gate low" in pit_get_out()
> here as well, right away? I was hoping to get away without ...
> (Note how the two functions also disagree in their placement of the
> "default" labels, even if that's largely benign when taking into
> account that modes 6 and 7 are transformed to 2 and 3 respectively
> by pit_load(). A difference would occur only before the guest first
> sets the mode, as pit_reset() sets it to 7.)
I'm in general afraid of doing changes here (apart from bugfixes)
because we don't really have a good way to test them AFAIK, maybe you
do have some XTF or similar tests to exercise those paths?
> Other observations:
> - Loading of new counts occurs too early in some of the modes (2/3: at
> end of current sequence or when gate goes high; 1/5: only when gate
> goes high).
> - BCD counting doesn't appear to be properly supported either (at least
> that's mentioned in the public header).
>
> [2] https://lists.xen.org/archives/html/xen-devel/2023-05/msg00887.html
>
> --- a/xen/arch/x86/emul-i8254.c
> +++ b/xen/arch/x86/emul-i8254.c
> @@ -65,7 +65,10 @@ static int pit_get_count(PITState *pit,
>
> ASSERT(spin_is_locked(&pit->lock));
>
> - d = muldiv64(get_guest_time(v) - pit->count_load_time[channel],
> + d = pit->hw.channels[channel].gate || (c->mode & 3) == 1
> + ? get_guest_time(v) - pit->count_load_time[channel]
> + : pit->count_stop_time[channel];
> + d = muldiv64(d - pit->stopped_time[channel],
> PIT_FREQ, SYSTEM_TIME_HZ);
>
> switch ( c->mode )
> @@ -109,6 +112,7 @@ static void pit_load_count(PITState *pit
> pit->count_load_time[channel] = 0;
> else
> pit->count_load_time[channel] = get_guest_time(v);
> + pit->stopped_time[channel] = 0;
Don't you need to also set count_stop_time == count_load_time in case
the counter is disabled? (s->gate == 0).
> s->count = val;
> period = DIV_ROUND(val * SYSTEM_TIME_HZ, PIT_FREQ);
>
> @@ -147,7 +151,10 @@ static int pit_get_out(PITState *pit, in
>
> ASSERT(spin_is_locked(&pit->lock));
>
> - d = muldiv64(get_guest_time(v) - pit->count_load_time[channel],
> + d = pit->hw.channels[channel].gate || (s->mode & 3) == 1
> + ? get_guest_time(v) - pit->count_load_time[channel]
> + : pit->count_stop_time[channel];
> + d = muldiv64(d - pit->stopped_time[channel],
> PIT_FREQ, SYSTEM_TIME_HZ);
>
> switch ( s->mode )
> @@ -181,22 +188,39 @@ static void pit_set_gate(PITState *pit,
>
> ASSERT(spin_is_locked(&pit->lock));
>
> - switch ( s->mode )
> - {
> - default:
> - case 0:
> - case 4:
> - /* XXX: just disable/enable counting */
> - break;
> - case 1:
> - case 5:
> - case 2:
> - case 3:
> - /* Restart counting on rising edge. */
> - if ( s->gate < val )
> - pit->count_load_time[channel] = get_guest_time(v);
> - break;
> - }
> + if ( s->gate > val )
> + switch ( s->mode )
> + {
> + case 0:
> + case 2:
> + case 3:
> + case 4:
> + /* Disable counting. */
> + if ( !channel )
> + destroy_periodic_time(&pit->pt0);
> + pit->count_stop_time[channel] = get_guest_time(v);
> + break;
> + }
> +
> + if ( s->gate < val )
Shouldn't this be an else if?
Thanks, Roger.
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |