[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v3 1/1] x86/acpi: Use FADT flags to determine the PMTMR width
On Fri, Jun 19, 2020 at 10:00:16PM +0000, Grzegorz Uriasz wrote: > On some computers the bit width of the PM Timer as reported > by ACPI is 32 bits when in fact the FADT flags report correctly > that the timer is 24 bits wide. On affected machines such as the > ASUS FX504GM and never gaming laptops this results in the inability > to resume the machine from suspend. Without this patch suspend is > broken on affected machines and even if a machine manages to resume > correctly then the kernel time and xen timers are trashed. > > Signed-off-by: Grzegorz Uriasz <gorbak25@xxxxxxxxx> > --- > Cc: Jan Beulich <jbeulich@xxxxxxxx> > Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> > Cc: Wei Liu <wl@xxxxxxx> > Cc: "Roger Pau Monné" <roger.pau@xxxxxxxxxx> > Cc: marmarek@xxxxxxxxxxxxxxxxxxxxxx > Cc: contact@xxxxxxxxxxxx > Cc: jakub@xxxxxxxxxxx > Cc: j.nowak26@xxxxxxxxxxxxxxxxx > > Changes in v2: > - Check pm timer access width > - Proper timer width is set when xpm block is not present > - Cleanup timer initialization > > Changes in v3: > - Check pm timer bit offset > - Warn about acpi firmware bugs > - Drop int cast in init_pmtimer > - Merge if's in init_pmtimer > --- > xen/arch/x86/acpi/boot.c | 19 +++++++++++++++---- > xen/arch/x86/time.c | 12 ++++-------- > xen/include/acpi/acmacros.h | 8 ++++++++ > 3 files changed, 27 insertions(+), 12 deletions(-) > > diff --git a/xen/arch/x86/acpi/boot.c b/xen/arch/x86/acpi/boot.c > index bcba52e232..24fd236eb5 100644 > --- a/xen/arch/x86/acpi/boot.c > +++ b/xen/arch/x86/acpi/boot.c > @@ -475,10 +475,17 @@ static int __init acpi_parse_fadt(struct > acpi_table_header *table) > > #ifdef CONFIG_X86_PM_TIMER > /* detect the location of the ACPI PM Timer */ > - if (fadt->header.revision >= FADT2_REVISION_ID) { > + if (fadt->header.revision >= FADT2_REVISION_ID && > + fadt->xpm_timer_block.space_id == ACPI_ADR_SPACE_SYSTEM_IO) { > /* FADT rev. 2 */ > - if (fadt->xpm_timer_block.space_id == > - ACPI_ADR_SPACE_SYSTEM_IO) { > + if (fadt->xpm_timer_block.access_width != 0 && > + ACPI_ACCESS_BIT_WIDTH(fadt->xpm_timer_block.access_width) > != 32) > + printk(KERN_WARNING PREFIX "PM-Timer has invalid access > width(%u)\n", > + fadt->xpm_timer_block.access_width); > + else if (fadt->xpm_timer_block.bit_offset != 0) This should be a plain if instead of an else if, it's possible the block has both the access_width and the bit_offset wrong. > + printk(KERN_WARNING PREFIX "PM-Timer has invalid bit > offset(%u)\n", > + fadt->xpm_timer_block.bit_offset); > + else { > pmtmr_ioport = fadt->xpm_timer_block.address; > pmtmr_width = fadt->xpm_timer_block.bit_width; > } > @@ -490,8 +497,12 @@ static int __init acpi_parse_fadt(struct > acpi_table_header *table) > */ > if (!pmtmr_ioport) { > pmtmr_ioport = fadt->pm_timer_block; > - pmtmr_width = fadt->pm_timer_length == 4 ? 24 : 0; > + pmtmr_width = fadt->pm_timer_length == 4 ? 32 : 0; > } > + if (pmtmr_width < 32 && fadt->flags & ACPI_FADT_32BIT_TIMER) > + printk(KERN_WARNING PREFIX "PM-Timer is too short\n"); Indentation. Also this should be a fatal error likely? You should set pmtmr_ioport = 0? > + if (pmtmr_width > 24 && !(fadt->flags & ACPI_FADT_32BIT_TIMER)) > + pmtmr_width = 24; > if (pmtmr_ioport) > printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x (%u bits)\n", > pmtmr_ioport, pmtmr_width); > diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c > index d643590c0a..8a45514908 100644 > --- a/xen/arch/x86/time.c > +++ b/xen/arch/x86/time.c > @@ -457,16 +457,13 @@ static u64 read_pmtimer_count(void) > static s64 __init init_pmtimer(struct platform_timesource *pts) > { > u64 start; > - u32 count, target, mask = 0xffffff; > + u32 count, target, mask; > > - if ( !pmtmr_ioport || !pmtmr_width ) > + if ( !pmtmr_ioport || (pmtmr_width != 24 && pmtmr_width != 32) ) > return 0; > > - if ( pmtmr_width == 32 ) > - { > - pts->counter_bits = 32; > - mask = 0xffffffff; > - } > + pts->counter_bits = pmtmr_width; > + mask = (1ull << pmtmr_width) - 1; > > count = inl(pmtmr_ioport) & mask; > start = rdtsc_ordered(); > @@ -486,7 +483,6 @@ static struct platform_timesource __initdata plt_pmtimer = > .name = "ACPI PM Timer", > .frequency = ACPI_PM_FREQUENCY, > .read_counter = read_pmtimer_count, > - .counter_bits = 24, > .init = init_pmtimer > }; > > diff --git a/xen/include/acpi/acmacros.h b/xen/include/acpi/acmacros.h > index 6765535053..86c503c20f 100644 > --- a/xen/include/acpi/acmacros.h > +++ b/xen/include/acpi/acmacros.h > @@ -121,6 +121,14 @@ > #define ACPI_COMPARE_NAME(a,b) (!ACPI_STRNCMP (ACPI_CAST_PTR > (char,(a)), ACPI_CAST_PTR (char,(b)), ACPI_NAME_SIZE)) > #endif > > +/* > + * Algorithm to obtain access bit or byte width. > + * Can be used with access_width of struct acpi_generic_address and > access_size of > + * struct acpi_resource_generic_register. > + */ > +#define ACPI_ACCESS_BIT_WIDTH(size) (1 << ((size) + 2)) > +#define ACPI_ACCESS_BYTE_WIDTH(size) (1 << ((size) - 1)) Note sure I would introduce this last one, since it's not used by the code. Thanks, Roger.
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |