diff mbox series

[3/4] vfio/igd: use PCI ID defines to detect IGD gen

Message ID 20250206121341.118337-4-corvin.koehne@gmail.com (mailing list archive)
State New
Headers show
Series vfio/igd: sync PCI IDs with i915 | expand

Commit Message

Corvin Köhne Feb. 6, 2025, 12:13 p.m. UTC
From: Corvin Köhne <c.koehne@beckhoff.com>

We've recently imported the PCI ID list of knwon Intel GPU devices from
Linux. It allows us to properly match GPUs to their generation without
maintaining an own list of PCI IDs.

Signed-off-by: Corvin Köhne <c.koehne@beckhoff.com>
---
 hw/vfio/igd.c | 77 ++++++++++++++++++++++++++++-----------------------
 1 file changed, 42 insertions(+), 35 deletions(-)

Comments

Alex Williamson Feb. 6, 2025, 9:26 p.m. UTC | #1
On Thu,  6 Feb 2025 13:13:39 +0100
Corvin Köhne <corvin.koehne@gmail.com> wrote:

> From: Corvin Köhne <c.koehne@beckhoff.com>
> 
> We've recently imported the PCI ID list of knwon Intel GPU devices from
> Linux. It allows us to properly match GPUs to their generation without
> maintaining an own list of PCI IDs.
> 
> Signed-off-by: Corvin Köhne <c.koehne@beckhoff.com>
> ---
>  hw/vfio/igd.c | 77 ++++++++++++++++++++++++++++-----------------------
>  1 file changed, 42 insertions(+), 35 deletions(-)
> 
> diff --git a/hw/vfio/igd.c b/hw/vfio/igd.c
> index 0740a5dd8c..e5d7006ce2 100644
> --- a/hw/vfio/igd.c
> +++ b/hw/vfio/igd.c
> @@ -18,6 +18,7 @@
>  #include "hw/hw.h"
>  #include "hw/nvram/fw_cfg.h"
>  #include "pci.h"
> +#include "standard-headers/drm/intel/pciids.h"
>  #include "trace.h"
>  
>  /*
> @@ -51,6 +52,42 @@
>   * headless setup is desired, the OpRegion gets in the way of that.
>   */
>  
> +struct igd_device {
> +    const uint32_t device_id;
> +    const int gen;
> +};
> +
> +#define IGD_DEVICE(_id, _gen) { \
> +    .device_id = (_id), \
> +    .gen = (_gen), \
> +}
> +
> +static const struct igd_device igd_devices[] = {
> +    INTEL_SNB_IDS(IGD_DEVICE, 6),
> +    INTEL_IVB_IDS(IGD_DEVICE, 6),
> +    INTEL_HSW_IDS(IGD_DEVICE, 7),
> +    INTEL_VLV_IDS(IGD_DEVICE, 7),
> +    INTEL_BDW_IDS(IGD_DEVICE, 8),
> +    INTEL_CHV_IDS(IGD_DEVICE, 8),
> +    INTEL_SKL_IDS(IGD_DEVICE, 9),
> +    INTEL_BXT_IDS(IGD_DEVICE, 9),
> +    INTEL_KBL_IDS(IGD_DEVICE, 9),
> +    INTEL_CFL_IDS(IGD_DEVICE, 9),
> +    INTEL_CML_IDS(IGD_DEVICE, 9),
> +    INTEL_GLK_IDS(IGD_DEVICE, 9),
> +    INTEL_ICL_IDS(IGD_DEVICE, 11),
> +    INTEL_EHL_IDS(IGD_DEVICE, 11),
> +    INTEL_JSL_IDS(IGD_DEVICE, 11),
> +    INTEL_TGL_IDS(IGD_DEVICE, 12),
> +    INTEL_RKL_IDS(IGD_DEVICE, 12),
> +    INTEL_ADLS_IDS(IGD_DEVICE, 12),
> +    INTEL_ADLP_IDS(IGD_DEVICE, 12),
> +    INTEL_ADLN_IDS(IGD_DEVICE, 12),
> +    INTEL_RPLS_IDS(IGD_DEVICE, 12),
> +    INTEL_RPLU_IDS(IGD_DEVICE, 12),
> +    INTEL_RPLP_IDS(IGD_DEVICE, 12),
> +};

I agree with Connie's comment on the ordering and content of the first
two patches.

For these last two, I wish these actually made it substantially easier
to synchronize with upstream.  Based on the next patch, I think it
still requires manually tracking/parsing internal code in the i915
driver to extract generation information.

Is it possible that we could split the above into a separate file
that's auto-generated from a script?  For example maybe some scripting
and C code that can instantiate the pciidlist array from i915_pci.c and
regurgitate it into a device-id/generation table?  Thanks,

Alex

> +
>  /*
>   * This presumes the device is already known to be an Intel VGA device, so we
>   * take liberties in which device ID bits match which generation.  This should
> @@ -60,42 +97,12 @@
>   */
>  static int igd_gen(VFIOPCIDevice *vdev)
>  {
> -    /*
> -     * Device IDs for Broxton/Apollo Lake are 0x0a84, 0x1a84, 0x1a85, 0x5a84
> -     * and 0x5a85, match bit 11:1 here
> -     * Prefix 0x0a is taken by Haswell, this rule should be matched first.
> -     */
> -    if ((vdev->device_id & 0xffe) == 0xa84) {
> -        return 9;
> -    }
> +    for (int i = 0; i < ARRAY_SIZE(igd_devices); i++) {
> +        if (igd_devices[i].device_id != vdev->device_id) {
> +            continue;
> +        }
>  
> -    switch (vdev->device_id & 0xff00) {
> -    case 0x0100:    /* SandyBridge, IvyBridge */
> -        return 6;
> -    case 0x0400:    /* Haswell */
> -    case 0x0a00:    /* Haswell */
> -    case 0x0c00:    /* Haswell */
> -    case 0x0d00:    /* Haswell */
> -    case 0x0f00:    /* Valleyview/Bay Trail */
> -        return 7;
> -    case 0x1600:    /* Broadwell */
> -    case 0x2200:    /* Cherryview */
> -        return 8;
> -    case 0x1900:    /* Skylake */
> -    case 0x3100:    /* Gemini Lake */
> -    case 0x5900:    /* Kaby Lake */
> -    case 0x3e00:    /* Coffee Lake */
> -    case 0x9B00:    /* Comet Lake */
> -        return 9;
> -    case 0x8A00:    /* Ice Lake */
> -    case 0x4500:    /* Elkhart Lake */
> -    case 0x4E00:    /* Jasper Lake */
> -        return 11;
> -    case 0x9A00:    /* Tiger Lake */
> -    case 0x4C00:    /* Rocket Lake */
> -    case 0x4600:    /* Alder Lake */
> -    case 0xA700:    /* Raptor Lake */
> -        return 12;
> +        return igd_devices[i].gen;
>      }
>  
>      /*
Corvin Köhne Feb. 7, 2025, 7:47 a.m. UTC | #2
On Thu, 2025-02-06 at 14:26 -0700, Alex Williamson wrote:
> On Thu,  6 Feb 2025 13:13:39 +0100
> Corvin Köhne <corvin.koehne@gmail.com> wrote:
> 
> > From: Corvin Köhne <c.koehne@beckhoff.com>
> > 
> > We've recently imported the PCI ID list of knwon Intel GPU devices from
> > Linux. It allows us to properly match GPUs to their generation without
> > maintaining an own list of PCI IDs.
> > 
> > Signed-off-by: Corvin Köhne <c.koehne@beckhoff.com>
> > ---
> >  hw/vfio/igd.c | 77 ++++++++++++++++++++++++++++-----------------------
> >  1 file changed, 42 insertions(+), 35 deletions(-)
> > 
> > diff --git a/hw/vfio/igd.c b/hw/vfio/igd.c
> > index 0740a5dd8c..e5d7006ce2 100644
> > --- a/hw/vfio/igd.c
> > +++ b/hw/vfio/igd.c
> > @@ -18,6 +18,7 @@
> >  #include "hw/hw.h"
> >  #include "hw/nvram/fw_cfg.h"
> >  #include "pci.h"
> > +#include "standard-headers/drm/intel/pciids.h"
> >  #include "trace.h"
> >  
> >  /*
> > @@ -51,6 +52,42 @@
> >   * headless setup is desired, the OpRegion gets in the way of that.
> >   */
> >  
> > +struct igd_device {
> > +    const uint32_t device_id;
> > +    const int gen;
> > +};
> > +
> > +#define IGD_DEVICE(_id, _gen) { \
> > +    .device_id = (_id), \
> > +    .gen = (_gen), \
> > +}
> > +
> > +static const struct igd_device igd_devices[] = {
> > +    INTEL_SNB_IDS(IGD_DEVICE, 6),
> > +    INTEL_IVB_IDS(IGD_DEVICE, 6),
> > +    INTEL_HSW_IDS(IGD_DEVICE, 7),
> > +    INTEL_VLV_IDS(IGD_DEVICE, 7),
> > +    INTEL_BDW_IDS(IGD_DEVICE, 8),
> > +    INTEL_CHV_IDS(IGD_DEVICE, 8),
> > +    INTEL_SKL_IDS(IGD_DEVICE, 9),
> > +    INTEL_BXT_IDS(IGD_DEVICE, 9),
> > +    INTEL_KBL_IDS(IGD_DEVICE, 9),
> > +    INTEL_CFL_IDS(IGD_DEVICE, 9),
> > +    INTEL_CML_IDS(IGD_DEVICE, 9),
> > +    INTEL_GLK_IDS(IGD_DEVICE, 9),
> > +    INTEL_ICL_IDS(IGD_DEVICE, 11),
> > +    INTEL_EHL_IDS(IGD_DEVICE, 11),
> > +    INTEL_JSL_IDS(IGD_DEVICE, 11),
> > +    INTEL_TGL_IDS(IGD_DEVICE, 12),
> > +    INTEL_RKL_IDS(IGD_DEVICE, 12),
> > +    INTEL_ADLS_IDS(IGD_DEVICE, 12),
> > +    INTEL_ADLP_IDS(IGD_DEVICE, 12),
> > +    INTEL_ADLN_IDS(IGD_DEVICE, 12),
> > +    INTEL_RPLS_IDS(IGD_DEVICE, 12),
> > +    INTEL_RPLU_IDS(IGD_DEVICE, 12),
> > +    INTEL_RPLP_IDS(IGD_DEVICE, 12),
> > +};
> 
> I agree with Connie's comment on the ordering and content of the first
> two patches.
> 
> For these last two, I wish these actually made it substantially easier
> to synchronize with upstream.  Based on the next patch, I think it
> still requires manually tracking/parsing internal code in the i915
> driver to extract generation information.
> 
> Is it possible that we could split the above into a separate file
> that's auto-generated from a script?  For example maybe some scripting
> and C code that can instantiate the pciidlist array from i915_pci.c and
> regurgitate it into a device-id/generation table?  Thanks,
> 
> Alex
> 

Hi Alex,

I took a closer look into i915 and it seems hard to parse. Upstream maintains a
description for each generation, e.g. on AlderLake P [1] the generation is
defined in the .info field of a struct, the .info field itself is defined
somewhere else [2] and sets the .__runtime_defaults.ip.ver by another C macro
[3]. Other platforms like GeminiLake set the .ip.ver directly in their
description struct [4].

Nevertheless, we may not need this PCI ID mapping at all in the future. It looks
like Intel added a new register to their GPU starting with MeteorLake [5]. We
can read it to obtain the GPU generation [6]. I don't have a MeteorLake system
available yet, so I can't test it. On my TigerLake system, the register returns
zero. When it works as expected, we could refactor the igd_gen function to
something like:

static int igd_gen(VFIOPCIDevice vdev) {
  uint32_t gmd_id = vfio_region_read(&vdev->bars[0].region, GMD_ID_DISPLAY, 4);
  if (gmd_id != 0) {
    return (gmd_id & GMD_ID_ARCH_MASK) >> GMD_ID_ARCH_SHIFT;
  }

  // Fallback to PCI ID mapping.
  ... 
}

[1]
https://elixir.bootlin.com/linux/v6.13.1/source/drivers/gpu/drm/i915/display/intel_display_device.c#L1171
[2]
https://elixir.bootlin.com/linux/v6.13.1/source/drivers/gpu/drm/i915/display/intel_display_device.c#L1128
[3]
https://elixir.bootlin.com/linux/v6.13.1/source/drivers/gpu/drm/i915/display/intel_display_device.c#L1120
[4]
https://elixir.bootlin.com/linux/v6.13.1/source/drivers/gpu/drm/i915/display/intel_display_device.c#L829
[5]
https://elixir.bootlin.com/linux/v6.13.1/source/drivers/gpu/drm/i915/display/intel_display_device.c#L1326-L1330
[6]
https://elixir.bootlin.com/linux/v6.13.1/source/drivers/gpu/drm/i915/display/intel_display_device.c#L1432
Corvin Köhne Feb. 7, 2025, 8:08 a.m. UTC | #3
On Fri, 2025-02-07 at 08:47 +0100, Corvin Köhne wrote:
> On Thu, 2025-02-06 at 14:26 -0700, Alex Williamson wrote:
> > On Thu,  6 Feb 2025 13:13:39 +0100
> > Corvin Köhne <corvin.koehne@gmail.com> wrote:
> > 
> > > From: Corvin Köhne <c.koehne@beckhoff.com>
> > > 
> > > We've recently imported the PCI ID list of knwon Intel GPU devices from
> > > Linux. It allows us to properly match GPUs to their generation without
> > > maintaining an own list of PCI IDs.
> > > 
> > > Signed-off-by: Corvin Köhne <c.koehne@beckhoff.com>
> > > ---
> > >  hw/vfio/igd.c | 77 ++++++++++++++++++++++++++++-----------------------
> > >  1 file changed, 42 insertions(+), 35 deletions(-)
> > > 
> > > diff --git a/hw/vfio/igd.c b/hw/vfio/igd.c
> > > index 0740a5dd8c..e5d7006ce2 100644
> > > --- a/hw/vfio/igd.c
> > > +++ b/hw/vfio/igd.c
> > > @@ -18,6 +18,7 @@
> > >  #include "hw/hw.h"
> > >  #include "hw/nvram/fw_cfg.h"
> > >  #include "pci.h"
> > > +#include "standard-headers/drm/intel/pciids.h"
> > >  #include "trace.h"
> > >  
> > >  /*
> > > @@ -51,6 +52,42 @@
> > >   * headless setup is desired, the OpRegion gets in the way of that.
> > >   */
> > >  
> > > +struct igd_device {
> > > +    const uint32_t device_id;
> > > +    const int gen;
> > > +};
> > > +
> > > +#define IGD_DEVICE(_id, _gen) { \
> > > +    .device_id = (_id), \
> > > +    .gen = (_gen), \
> > > +}
> > > +
> > > +static const struct igd_device igd_devices[] = {
> > > +    INTEL_SNB_IDS(IGD_DEVICE, 6),
> > > +    INTEL_IVB_IDS(IGD_DEVICE, 6),
> > > +    INTEL_HSW_IDS(IGD_DEVICE, 7),
> > > +    INTEL_VLV_IDS(IGD_DEVICE, 7),
> > > +    INTEL_BDW_IDS(IGD_DEVICE, 8),
> > > +    INTEL_CHV_IDS(IGD_DEVICE, 8),
> > > +    INTEL_SKL_IDS(IGD_DEVICE, 9),
> > > +    INTEL_BXT_IDS(IGD_DEVICE, 9),
> > > +    INTEL_KBL_IDS(IGD_DEVICE, 9),
> > > +    INTEL_CFL_IDS(IGD_DEVICE, 9),
> > > +    INTEL_CML_IDS(IGD_DEVICE, 9),
> > > +    INTEL_GLK_IDS(IGD_DEVICE, 9),
> > > +    INTEL_ICL_IDS(IGD_DEVICE, 11),
> > > +    INTEL_EHL_IDS(IGD_DEVICE, 11),
> > > +    INTEL_JSL_IDS(IGD_DEVICE, 11),
> > > +    INTEL_TGL_IDS(IGD_DEVICE, 12),
> > > +    INTEL_RKL_IDS(IGD_DEVICE, 12),
> > > +    INTEL_ADLS_IDS(IGD_DEVICE, 12),
> > > +    INTEL_ADLP_IDS(IGD_DEVICE, 12),
> > > +    INTEL_ADLN_IDS(IGD_DEVICE, 12),
> > > +    INTEL_RPLS_IDS(IGD_DEVICE, 12),
> > > +    INTEL_RPLU_IDS(IGD_DEVICE, 12),
> > > +    INTEL_RPLP_IDS(IGD_DEVICE, 12),
> > > +};
> > 
> > I agree with Connie's comment on the ordering and content of the first
> > two patches.
> > 
> > For these last two, I wish these actually made it substantially easier
> > to synchronize with upstream.  Based on the next patch, I think it
> > still requires manually tracking/parsing internal code in the i915
> > driver to extract generation information.
> > 
> > Is it possible that we could split the above into a separate file
> > that's auto-generated from a script?  For example maybe some scripting
> > and C code that can instantiate the pciidlist array from i915_pci.c and
> > regurgitate it into a device-id/generation table?  Thanks,
> > 
> > Alex
> > 
> 
> Hi Alex,
> 
> I took a closer look into i915 and it seems hard to parse. Upstream maintains
> a
> description for each generation, e.g. on AlderLake P [1] the generation is
> defined in the .info field of a struct, the .info field itself is defined
> somewhere else [2] and sets the .__runtime_defaults.ip.ver by another C macro
> [3]. Other platforms like GeminiLake set the .ip.ver directly in their
> description struct [4].
> 
> Nevertheless, we may not need this PCI ID mapping at all in the future. It
> looks
> like Intel added a new register to their GPU starting with MeteorLake [5]. We
> can read it to obtain the GPU generation [6]. I don't have a MeteorLake system
> available yet, so I can't test it. On my TigerLake system, the register
> returns
> zero. When it works as expected, we could refactor the igd_gen function to
> something like:
> 
> static int igd_gen(VFIOPCIDevice vdev) {
>   uint32_t gmd_id = vfio_region_read(&vdev->bars[0].region, GMD_ID_DISPLAY,
> 4);
>   if (gmd_id != 0) {
>     return (gmd_id & GMD_ID_ARCH_MASK) >> GMD_ID_ARCH_SHIFT;
>   }
> 
>   // Fallback to PCI ID mapping.
>   ... 
> }
> 
> [1]
> https://elixir.bootlin.com/linux/v6.13.1/source/drivers/gpu/drm/i915/display/intel_display_device.c#L1171
> [2]
> https://elixir.bootlin.com/linux/v6.13.1/source/drivers/gpu/drm/i915/display/intel_display_device.c#L1128
> [3]
> https://elixir.bootlin.com/linux/v6.13.1/source/drivers/gpu/drm/i915/display/intel_display_device.c#L1120
> [4]
> https://elixir.bootlin.com/linux/v6.13.1/source/drivers/gpu/drm/i915/display/intel_display_device.c#L829
> [5]
> https://elixir.bootlin.com/linux/v6.13.1/source/drivers/gpu/drm/i915/display/intel_display_device.c#L1326-L1330
> [6]
> https://elixir.bootlin.com/linux/v6.13.1/source/drivers/gpu/drm/i915/display/intel_display_device.c#L1432
> 
> 

I've missed that upstream maintains a second list [1]. Nevertheless, it looks
still hard to parse.

[1]
https://elixir.bootlin.com/linux/v6.13.1/source/drivers/gpu/drm/i915/i915_pci.c
diff mbox series

Patch

diff --git a/hw/vfio/igd.c b/hw/vfio/igd.c
index 0740a5dd8c..e5d7006ce2 100644
--- a/hw/vfio/igd.c
+++ b/hw/vfio/igd.c
@@ -18,6 +18,7 @@ 
 #include "hw/hw.h"
 #include "hw/nvram/fw_cfg.h"
 #include "pci.h"
+#include "standard-headers/drm/intel/pciids.h"
 #include "trace.h"
 
 /*
@@ -51,6 +52,42 @@ 
  * headless setup is desired, the OpRegion gets in the way of that.
  */
 
+struct igd_device {
+    const uint32_t device_id;
+    const int gen;
+};
+
+#define IGD_DEVICE(_id, _gen) { \
+    .device_id = (_id), \
+    .gen = (_gen), \
+}
+
+static const struct igd_device igd_devices[] = {
+    INTEL_SNB_IDS(IGD_DEVICE, 6),
+    INTEL_IVB_IDS(IGD_DEVICE, 6),
+    INTEL_HSW_IDS(IGD_DEVICE, 7),
+    INTEL_VLV_IDS(IGD_DEVICE, 7),
+    INTEL_BDW_IDS(IGD_DEVICE, 8),
+    INTEL_CHV_IDS(IGD_DEVICE, 8),
+    INTEL_SKL_IDS(IGD_DEVICE, 9),
+    INTEL_BXT_IDS(IGD_DEVICE, 9),
+    INTEL_KBL_IDS(IGD_DEVICE, 9),
+    INTEL_CFL_IDS(IGD_DEVICE, 9),
+    INTEL_CML_IDS(IGD_DEVICE, 9),
+    INTEL_GLK_IDS(IGD_DEVICE, 9),
+    INTEL_ICL_IDS(IGD_DEVICE, 11),
+    INTEL_EHL_IDS(IGD_DEVICE, 11),
+    INTEL_JSL_IDS(IGD_DEVICE, 11),
+    INTEL_TGL_IDS(IGD_DEVICE, 12),
+    INTEL_RKL_IDS(IGD_DEVICE, 12),
+    INTEL_ADLS_IDS(IGD_DEVICE, 12),
+    INTEL_ADLP_IDS(IGD_DEVICE, 12),
+    INTEL_ADLN_IDS(IGD_DEVICE, 12),
+    INTEL_RPLS_IDS(IGD_DEVICE, 12),
+    INTEL_RPLU_IDS(IGD_DEVICE, 12),
+    INTEL_RPLP_IDS(IGD_DEVICE, 12),
+};
+
 /*
  * This presumes the device is already known to be an Intel VGA device, so we
  * take liberties in which device ID bits match which generation.  This should
@@ -60,42 +97,12 @@ 
  */
 static int igd_gen(VFIOPCIDevice *vdev)
 {
-    /*
-     * Device IDs for Broxton/Apollo Lake are 0x0a84, 0x1a84, 0x1a85, 0x5a84
-     * and 0x5a85, match bit 11:1 here
-     * Prefix 0x0a is taken by Haswell, this rule should be matched first.
-     */
-    if ((vdev->device_id & 0xffe) == 0xa84) {
-        return 9;
-    }
+    for (int i = 0; i < ARRAY_SIZE(igd_devices); i++) {
+        if (igd_devices[i].device_id != vdev->device_id) {
+            continue;
+        }
 
-    switch (vdev->device_id & 0xff00) {
-    case 0x0100:    /* SandyBridge, IvyBridge */
-        return 6;
-    case 0x0400:    /* Haswell */
-    case 0x0a00:    /* Haswell */
-    case 0x0c00:    /* Haswell */
-    case 0x0d00:    /* Haswell */
-    case 0x0f00:    /* Valleyview/Bay Trail */
-        return 7;
-    case 0x1600:    /* Broadwell */
-    case 0x2200:    /* Cherryview */
-        return 8;
-    case 0x1900:    /* Skylake */
-    case 0x3100:    /* Gemini Lake */
-    case 0x5900:    /* Kaby Lake */
-    case 0x3e00:    /* Coffee Lake */
-    case 0x9B00:    /* Comet Lake */
-        return 9;
-    case 0x8A00:    /* Ice Lake */
-    case 0x4500:    /* Elkhart Lake */
-    case 0x4E00:    /* Jasper Lake */
-        return 11;
-    case 0x9A00:    /* Tiger Lake */
-    case 0x4C00:    /* Rocket Lake */
-    case 0x4600:    /* Alder Lake */
-    case 0xA700:    /* Raptor Lake */
-        return 12;
+        return igd_devices[i].gen;
     }
 
     /*