diff mbox series

[v5,1/5] x86/quirks: Fix stolen detection with integrated + discrete GPU

Message ID 20220114002843.2083382-1-lucas.demarchi@intel.com
State New
Headers show
Series [v5,1/5] x86/quirks: Fix stolen detection with integrated + discrete GPU | expand

Commit Message

Lucas De Marchi Jan. 14, 2022, 12:28 a.m. UTC
early_pci_scan_bus() does a depth-first traversal, possibly calling
the quirk functions for each device based on vendor, device and class
from early_qrk table. intel_graphics_quirks() however uses PCI_ANY_ID
and does additional filtering in the quirk.

If there is an Intel integrated + discrete GPU the quirk may be called
first for the discrete GPU based on the PCI topology. Then we will fail
to reserve the system stolen memory for the integrated GPU, because we
will already have marked the quirk as "applied".

This was reproduced in a setup with Alderlake-P (integrated) + DG2
(discrete), with the following PCI topology:

	- 00:01.0 Bridge
	  `- 03:00.0 DG2
	- 00:02.0 Integrated GPU

So, stop using the QFLAG_APPLY_ONCE flag, replacing it with a static
local variable. We can set this variable in the right place, inside
intel_graphics_quirks(), only when the quirk was actually applied, i.e.
when we find the integrated GPU based on the intel_early_ids table.

Cc: stable@vger.kernel.org
Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
---

v5: apply fix before the refactor

 arch/x86/kernel/early-quirks.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

Comments

Borislav Petkov Jan. 18, 2022, 9:40 a.m. UTC | #1
n Thu, Jan 13, 2022 at 04:28:39PM -0800, Lucas De Marchi wrote:
> early_pci_scan_bus() does a depth-first traversal, possibly calling
> the quirk functions for each device based on vendor, device and class
> from early_qrk table. intel_graphics_quirks() however uses PCI_ANY_ID
> and does additional filtering in the quirk.
> 
> If there is an Intel integrated + discrete GPU the quirk may be called
> first for the discrete GPU based on the PCI topology. Then we will fail
> to reserve the system stolen memory for the integrated GPU, because we
> will already have marked the quirk as "applied".

Who is "we"?

Please use passive voice in your commit message: no "we" or "I", etc,
and describe your changes in imperative mood.

Bottom line is: personal pronouns are ambiguous in text, especially with
so many parties/companies/etc developing the kernel so let's avoid them
please.

> This was reproduced in a setup with Alderlake-P (integrated) + DG2
> (discrete), with the following PCI topology:
> 
> 	- 00:01.0 Bridge
> 	  `- 03:00.0 DG2
> 	- 00:02.0 Integrated GPU
> 
> So, stop using the QFLAG_APPLY_ONCE flag, replacing it with a static
> local variable. We can set this variable in the right place, inside
> intel_graphics_quirks(), only when the quirk was actually applied, i.e.
> when we find the integrated GPU based on the intel_early_ids table.
> 
> Cc: stable@vger.kernel.org
> Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
> ---
> 
> v5: apply fix before the refactor
> 
>  arch/x86/kernel/early-quirks.c | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
> index 1ca3a56fdc2d..de9a76eb544e 100644
> --- a/arch/x86/kernel/early-quirks.c
> +++ b/arch/x86/kernel/early-quirks.c
> @@ -589,10 +589,14 @@ intel_graphics_stolen(int num, int slot, int func,
>  
>  static void __init intel_graphics_quirks(int num, int slot, int func)
>  {
> +	static bool quirk_applied __initdata;
>  	const struct intel_early_ops *early_ops;
>  	u16 device;
>  	int i;
>  
> +	if (quirk_applied)
> +		return;
> +
>  	device = read_pci_config_16(num, slot, func, PCI_DEVICE_ID);
>  
>  	for (i = 0; i < ARRAY_SIZE(intel_early_ids); i++) {
> @@ -605,6 +609,8 @@ static void __init intel_graphics_quirks(int num, int slot, int func)
>  
>  		intel_graphics_stolen(num, slot, func, early_ops);
>  
> +		quirk_applied = true;
> +
>  		return;
>  	}

So I wonder: why can't you simply pass in a static struct chipset *
pointer into the early_qrk[i].f function and in there you can set
QFLAG_APPLIED or so, so that you can mark that the quirk is applied by
using the nice, per-quirk flags someone has already added instead of
this ugly static variable?

Patch 3 especially makes me go, huh?
Lucas De Marchi Jan. 18, 2022, 4:36 p.m. UTC | #2
On Tue, Jan 18, 2022 at 10:40:50AM +0100, Borislav Petkov wrote:
>n Thu, Jan 13, 2022 at 04:28:39PM -0800, Lucas De Marchi wrote:
>> early_pci_scan_bus() does a depth-first traversal, possibly calling
>> the quirk functions for each device based on vendor, device and class
>> from early_qrk table. intel_graphics_quirks() however uses PCI_ANY_ID
>> and does additional filtering in the quirk.
>>
>> If there is an Intel integrated + discrete GPU the quirk may be called
>> first for the discrete GPU based on the PCI topology. Then we will fail
>> to reserve the system stolen memory for the integrated GPU, because we
>> will already have marked the quirk as "applied".
>
>Who is "we"?
>
>Please use passive voice in your commit message: no "we" or "I", etc,
>and describe your changes in imperative mood.
>
>Bottom line is: personal pronouns are ambiguous in text, especially with
>so many parties/companies/etc developing the kernel so let's avoid them
>please.

I had the impression the subject/title should be imperative, with it
more relaxed in the body. It seems we have one more difference among
subsystems and I will adapt on next submissions to x86.

To clarify, "we" here means whoever is reading and following the code
path. It has the same connotation as the others in
'git log --grep "we\s"'.  From a quick grep it seems Linus merges a lot
of pull requests using that language and he himself uses it in commit
messages. Example: commit 054aa8d439b9 ("fget: check that the fd still
exists after getting a ref to it"). I was also surprised he also uses it
in the first person in some commits.

>
>> This was reproduced in a setup with Alderlake-P (integrated) + DG2
>> (discrete), with the following PCI topology:
>>
>> 	- 00:01.0 Bridge
>> 	  `- 03:00.0 DG2
>> 	- 00:02.0 Integrated GPU
>>
>> So, stop using the QFLAG_APPLY_ONCE flag, replacing it with a static
>> local variable. We can set this variable in the right place, inside
>> intel_graphics_quirks(), only when the quirk was actually applied, i.e.
>> when we find the integrated GPU based on the intel_early_ids table.
>>
>> Cc: stable@vger.kernel.org
>> Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
>> ---
>>
>> v5: apply fix before the refactor
>>
>>  arch/x86/kernel/early-quirks.c | 8 +++++++-
>>  1 file changed, 7 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
>> index 1ca3a56fdc2d..de9a76eb544e 100644
>> --- a/arch/x86/kernel/early-quirks.c
>> +++ b/arch/x86/kernel/early-quirks.c
>> @@ -589,10 +589,14 @@ intel_graphics_stolen(int num, int slot, int func,
>>
>>  static void __init intel_graphics_quirks(int num, int slot, int func)
>>  {
>> +	static bool quirk_applied __initdata;
>>  	const struct intel_early_ops *early_ops;
>>  	u16 device;
>>  	int i;
>>
>> +	if (quirk_applied)
>> +		return;
>> +
>>  	device = read_pci_config_16(num, slot, func, PCI_DEVICE_ID);
>>
>>  	for (i = 0; i < ARRAY_SIZE(intel_early_ids); i++) {
>> @@ -605,6 +609,8 @@ static void __init intel_graphics_quirks(int num, int slot, int func)
>>
>>  		intel_graphics_stolen(num, slot, func, early_ops);
>>
>> +		quirk_applied = true;
>> +
>>  		return;
>>  	}
>
>So I wonder: why can't you simply pass in a static struct chipset *
>pointer into the early_qrk[i].f function and in there you can set
>QFLAG_APPLIED or so, so that you can mark that the quirk is applied by
>using the nice, per-quirk flags someone has already added instead of
>this ugly static variable?

It seems you prefer v1. See 20211218061313.100571-1-lucas.demarchi@intel.com

Although in the review Bjorn suggested just splitting the commit, it was
also mentioned that the PCI subsystem has no such logic in its
equivalent pci_do_fixups(): a quirk/fixup needing that should instead
use a static local.

After checking the code again I seconded his suggestion and adapted
on subsequent versions. Besides his comment on PCI subsystem I had these
motivations:

1) From a total o 11 quirks, only 3 were actually using that logic and 1
of them was wrong (the one being fixed here with the called vs applied
logic)

2) The resources these conditions are protecting are global to the
system: they all end up setting a variable - just having a static local
protecting the function from being called more than once seemed
appropriate to avoid that.

3) Even arch/x86 uses that for the PCI fixups
(arch/x86/kernel/quirks.c). It uses the logic "resource has already
been set" as opposed to adding static local since, but it seems similar
approach to me.


>
>Patch 3 especially makes me go, huh?

What is special about patch 3? Maybe the way it was split in v5 vs v4
made it not so clear: intention was not to change the current behavior
since it has been like this for 15+ years with no bug that I know of.
The previous approach would not call acpi_table_parse() twice for
example.

thanks
Lucas De Marchi

>
>-- 
>Regards/Gruss,
>    Boris.
>
>https://people.kernel.org/tglx/notes-about-netiquette
Borislav Petkov Jan. 18, 2022, 5:26 p.m. UTC | #3
On Tue, Jan 18, 2022 at 08:36:56AM -0800, Lucas De Marchi wrote:
> I had the impression the subject/title should be imperative, with it
> more relaxed in the body. It seems we have one more difference among
> subsystems and I will adapt on next submissions to x86.

We have written it down properly, in case it explains it better:

"The tip tree maintainers set value on following these rules, especially
on the request to write changelogs in imperative mood and not
impersonating code or the execution of it. This is not just a whim of
the maintainers. Changelogs written in abstract words are more precise
and tend to be less confusing than those written in the form of novels."

from Documentation/process/maintainer-tip.rst

> > So I wonder: why can't you simply pass in a static struct chipset *
> > pointer into the early_qrk[i].f function and in there you can set
> > QFLAG_APPLIED or so, so that you can mark that the quirk is applied by
> > using the nice, per-quirk flags someone has already added instead of
> > this ugly static variable?
> 
> It seems you prefer v1. See 20211218061313.100571-1-lucas.demarchi@intel.com

I do?

I don't see there:

	early_qrk[i].f(&early_qrk[i], num, slot, func)

so that the ->f callback can set the flags. Or at least the flags passed
in.

If it is not clear what I mean, pls say so and I'll try to produce an
example diff ontop.

> Although in the review Bjorn suggested just splitting the commit, it was
> also mentioned that the PCI subsystem has no such logic in its
> equivalent pci_do_fixups(): a quirk/fixup needing that should instead
> use a static local.

Why?

There's perfectly nice ->flags there for exactly stuff like that. static
vars are ugly and should be avoided if possible.

> What is special about patch 3?

Nothing special. It is just ugly.

Thx.
Bjorn Helgaas Jan. 18, 2022, 5:58 p.m. UTC | #4
On Tue, Jan 18, 2022 at 06:26:48PM +0100, Borislav Petkov wrote:
> On Tue, Jan 18, 2022 at 08:36:56AM -0800, Lucas De Marchi wrote:
> > I had the impression the subject/title should be imperative, with it
> > more relaxed in the body. It seems we have one more difference among
> > subsystems and I will adapt on next submissions to x86.
> 
> We have written it down properly, in case it explains it better:
> 
> "The tip tree maintainers set value on following these rules, especially
> on the request to write changelogs in imperative mood and not
> impersonating code or the execution of it. This is not just a whim of
> the maintainers. Changelogs written in abstract words are more precise
> and tend to be less confusing than those written in the form of novels."
> 
> from Documentation/process/maintainer-tip.rst

Thanks for writing this down!  I do the same for PCI.  I suspect this
is a pretty conservative style that would be acceptable tree-wide even
if not required everywhere.

> > Although in the review Bjorn suggested just splitting the commit, it was
> > also mentioned that the PCI subsystem has no such logic in its
> > equivalent pci_do_fixups(): a quirk/fixup needing that should instead
> > use a static local.
> 
> Why?

I don't really care much one way or the other.  I think the simplest
approach is to remove QFLAG_APPLY_ONCE from intel_graphics_quirks()
and do nothing else, as I suggested here:

  https://lore.kernel.org/r/20220113000805.GA295089@bhelgaas

Unfortunately that didn't occur to me until I'd already suggested more
complicated things that no longer seem worthwhile to me.

The static variable might be ugly, but it does seem to be what
intel_graphics_quirks() wants -- a "do this at most once per system
but we don't know exactly which device" situation.

> There's perfectly nice ->flags there for exactly stuff like that. static
> vars are ugly and should be avoided if possible.

Bjorn
Lucas De Marchi Jan. 18, 2022, 7:05 p.m. UTC | #5
On Tue, Jan 18, 2022 at 06:26:48PM +0100, Borislav Petkov wrote:
>On Tue, Jan 18, 2022 at 08:36:56AM -0800, Lucas De Marchi wrote:
>> I had the impression the subject/title should be imperative, with it
>> more relaxed in the body. It seems we have one more difference among
>> subsystems and I will adapt on next submissions to x86.
>
>We have written it down properly, in case it explains it better:
>
>"The tip tree maintainers set value on following these rules, especially
>on the request to write changelogs in imperative mood and not
>impersonating code or the execution of it. This is not just a whim of
>the maintainers. Changelogs written in abstract words are more precise
>and tend to be less confusing than those written in the form of novels."
>
>from Documentation/process/maintainer-tip.rst

nice, thanks. I had missed this. It certainly makes it easier to adapt
the style when crossing subystems

>> > So I wonder: why can't you simply pass in a static struct chipset *
>> > pointer into the early_qrk[i].f function and in there you can set
>> > QFLAG_APPLIED or so, so that you can mark that the quirk is applied by
>> > using the nice, per-quirk flags someone has already added instead of
>> > this ugly static variable?
>>
>> It seems you prefer v1. See 20211218061313.100571-1-lucas.demarchi@intel.com
>
>I do?
>
>I don't see there:
>
>	early_qrk[i].f(&early_qrk[i], num, slot, func)
>
>so that the ->f callback can set the flags. Or at least the flags passed
>in.

Indeed not exactly the same. In v1 we have

	applied = early_qrk[i].f(num, slot, func);

because I was trying to keep the logic that uses and the one that checks
the value in the same place. With your suggestion the logic to set the
flag would need to move to the called functions, while checking for the
flag would continue to be in the caller.

>If it is not clear what I mean, pls say so and I'll try to produce an
>example diff ontop.
>
>> Although in the review Bjorn suggested just splitting the commit, it was
>> also mentioned that the PCI subsystem has no such logic in its
>> equivalent pci_do_fixups(): a quirk/fixup needing that should instead
>> use a static local.
>
>Why?

I think to make it similar how the PCI fixups work. Anyway, do you
prefer that I change the QFLAG_APPLY_ONCE as above (including
nvidia_bugs() and ati_bugs()) or a very minimal fix like below and
nothing else?

------8<------
diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
index 391a4e2b8604..7b2a3230c42a 100644
--- a/arch/x86/kernel/early-quirks.c
+++ b/arch/x86/kernel/early-quirks.c
@@ -591,6 +591,13 @@ static void __init intel_graphics_quirks(int num, int slot, int func)
  	u16 device;
  	int i;
  
+	/*
+	 * Already reserved for integrated graphics, nothing to do for other
+	 * (discrete) cards.
+	 */
+	if (resource_size(&intel_graphics_stolen_res))
+		return;
+
  	device = read_pci_config_16(num, slot, func, PCI_DEVICE_ID);
  
  	for (i = 0; i < ARRAY_SIZE(intel_early_ids); i++) {
@@ -703,7 +710,7 @@ static struct chipset early_qrk[] __initdata = {
  	{ PCI_VENDOR_ID_INTEL, 0x3406, PCI_CLASS_BRIDGE_HOST,
  	  PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
  	{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA, PCI_ANY_ID,
-	  QFLAG_APPLY_ONCE, intel_graphics_quirks },
+	  0, intel_graphics_quirks },
  	/*
  	 * HPET on the current version of the Baytrail platform has accuracy
  	 * problems: it will halt in deep idle state - so we disable it.
------8<------


thanks
Lucas De Marchi
Borislav Petkov Jan. 18, 2022, 7:14 p.m. UTC | #6
On Tue, Jan 18, 2022 at 11:05:58AM -0800, Lucas De Marchi wrote:
> I think to make it similar how the PCI fixups work. Anyway, do you
> prefer that I change the QFLAG_APPLY_ONCE as above (including
> nvidia_bugs() and ati_bugs()) or a very minimal fix like below and
> nothing else?
> 
> ------8<------
> diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
> index 391a4e2b8604..7b2a3230c42a 100644
> --- a/arch/x86/kernel/early-quirks.c
> +++ b/arch/x86/kernel/early-quirks.c
> @@ -591,6 +591,13 @@ static void __init intel_graphics_quirks(int num, int slot, int func)
>  	u16 device;
>  	int i;
> +	/*
> +	 * Already reserved for integrated graphics, nothing to do for other
> +	 * (discrete) cards.
> +	 */
> +	if (resource_size(&intel_graphics_stolen_res))
> +		return;
> +
>  	device = read_pci_config_16(num, slot, func, PCI_DEVICE_ID);
>  	for (i = 0; i < ARRAY_SIZE(intel_early_ids); i++) {
> @@ -703,7 +710,7 @@ static struct chipset early_qrk[] __initdata = {
>  	{ PCI_VENDOR_ID_INTEL, 0x3406, PCI_CLASS_BRIDGE_HOST,
>  	  PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
>  	{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA, PCI_ANY_ID,
> -	  QFLAG_APPLY_ONCE, intel_graphics_quirks },
> +	  0, intel_graphics_quirks },
>  	/*
>  	 * HPET on the current version of the Baytrail platform has accuracy
>  	 * problems: it will halt in deep idle state - so we disable it.
> ------8<------

This looks even cleaner to me but that's Bjorn's call in the end.

Thx.
diff mbox series

Patch

diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
index 1ca3a56fdc2d..de9a76eb544e 100644
--- a/arch/x86/kernel/early-quirks.c
+++ b/arch/x86/kernel/early-quirks.c
@@ -589,10 +589,14 @@  intel_graphics_stolen(int num, int slot, int func,
 
 static void __init intel_graphics_quirks(int num, int slot, int func)
 {
+	static bool quirk_applied __initdata;
 	const struct intel_early_ops *early_ops;
 	u16 device;
 	int i;
 
+	if (quirk_applied)
+		return;
+
 	device = read_pci_config_16(num, slot, func, PCI_DEVICE_ID);
 
 	for (i = 0; i < ARRAY_SIZE(intel_early_ids); i++) {
@@ -605,6 +609,8 @@  static void __init intel_graphics_quirks(int num, int slot, int func)
 
 		intel_graphics_stolen(num, slot, func, early_ops);
 
+		quirk_applied = true;
+
 		return;
 	}
 }
@@ -705,7 +711,7 @@  static struct chipset early_qrk[] __initdata = {
 	{ PCI_VENDOR_ID_INTEL, 0x3406, PCI_CLASS_BRIDGE_HOST,
 	  PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
 	{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA, PCI_ANY_ID,
-	  QFLAG_APPLY_ONCE, intel_graphics_quirks },
+	  0, intel_graphics_quirks },
 	/*
 	 * HPET on the current version of the Baytrail platform has accuracy
 	 * problems: it will halt in deep idle state - so we disable it.