diff mbox series

[v2,2/8] video: Provide screen_info_get_pci_dev() to find screen_info's PCI device

Message ID 20240202120140.3517-3-tzimmermann@suse.de (mailing list archive)
State Superseded
Headers show
Series firmware/sysfb: Track parent device for screen_info | expand

Commit Message

Thomas Zimmermann Feb. 2, 2024, 11:58 a.m. UTC
Add screen_info_get_pci_dev() to find the PCI device of an instance
of screen_info. Does nothing on systems without PCI bus.

v2:
	* remove ret from screen_info_pci_dev() (Javier)

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
---
 drivers/video/Makefile          |  1 +
 drivers/video/screen_info_pci.c | 52 +++++++++++++++++++++++++++++++++
 include/linux/screen_info.h     | 10 +++++++
 3 files changed, 63 insertions(+)
 create mode 100644 drivers/video/screen_info_pci.c

Comments

Sui Jingfeng Feb. 2, 2024, 4:31 p.m. UTC | #1
Hi,


On 2024/2/2 19:58, Thomas Zimmermann wrote:
> diff --git a/drivers/video/screen_info_pci.c b/drivers/video/screen_info_pci.c
> new file mode 100644
> index 0000000000000..d959a4c6ba3d5
> --- /dev/null
> +++ b/drivers/video/screen_info_pci.c
> @@ -0,0 +1,52 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/pci.h>
> +#include <linux/screen_info.h>
> +
> +static struct pci_dev *__screen_info_pci_dev(struct resource *res)
> +{
> +	struct pci_dev *pdev;
> +
> +	if (!(res->flags & IORESOURCE_MEM))
> +		return NULL;
> +
> +	for_each_pci_dev(pdev) {
> +		const struct resource *r;
> +
> +		if ((pdev->class >> 16) != PCI_BASE_CLASS_DISPLAY)
> +			continue;
> +
> +		r = pci_find_resource(pdev, res);
> +		if (r)
> +			return pdev;
> +	}
> +
> +	return NULL;
> +}


I recommend using the pci_get_base_class() or pci_get_class() helper function at here,
for example:


static struct pci_dev *__screen_info_pci_dev(struct resource *res)
{
	struct pci_dev *pdev;

	if (!(res->flags & IORESOURCE_MEM))
		return NULL;

	while ((pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, pdev))) {
		if (pci_find_resource(pdev, res))
			return pdev;
	}

	return NULL;
}
Sui Jingfeng Feb. 2, 2024, 5:03 p.m. UTC | #2
Hi,


On 2024/2/2 19:58, Thomas Zimmermann wrote:
> +
> +/**
> + * screen_info_pci_dev() - Return PCI parent device that contains screen_info's framebuffer
> + * @si: the screen_info
> + *
> + * Returns:
> + * The screen_info's parent device on success, or NULL otherwise.
> + */
> +struct pci_dev *screen_info_pci_dev(const struct screen_info *si)
> +{
> +	struct resource res[SCREEN_INFO_MAX_RESOURCES];
> +	ssize_t i, numres;
> +
> +	numres = screen_info_resources(si, res, ARRAY_SIZE(res));
> +	if (numres < 0)
> +		return ERR_PTR(numres);


Please return NULL at here, otherwise we have to use the IS_ERR or IS_ERR_OR_NULL()
in the caller function to check the returned value. Meanwhile, I noticed that you
didn't actually call IS_ERR() in the sysfb_parent_dev() function (introduced by the
3/8 patch), so I think we probably should return NULL at here.

Please also consider that the comments of this function says that it return NULL on
the otherwise cases.


> +	for (i = 0; i < numres; ++i) {
> +		struct pci_dev *pdev = __screen_info_pci_dev(&res[i]);
> +
> +		if (pdev)
> +			return pdev;
> +	}
> +
> +	return NULL;
> +}
> +EXPORT_SYMBOL(screen_info_pci_dev);
kernel test robot Feb. 4, 2024, 1:53 a.m. UTC | #3
Hi Thomas,

kernel test robot noticed the following build warnings:

[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on drm-tip/drm-tip linus/master v6.8-rc2 next-20240202]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Thomas-Zimmermann/video-Add-helpers-for-decoding-screen_info/20240202-200314
base:   git://anongit.freedesktop.org/drm/drm-misc drm-misc-next
patch link:    https://lore.kernel.org/r/20240202120140.3517-3-tzimmermann%40suse.de
patch subject: [PATCH v2 2/8] video: Provide screen_info_get_pci_dev() to find screen_info's PCI device
config: i386-buildonly-randconfig-004-20240203 (https://download.01.org/0day-ci/archive/20240204/202402040957.xNqUV75N-lkp@intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240204/202402040957.xNqUV75N-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202402040957.xNqUV75N-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/video/screen_info_pci.c:10:6: warning: variable 'pdev' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
      10 |         if (!(res->flags & IORESOURCE_MEM))
         |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/video/screen_info_pci.c:13:19: note: uninitialized use occurs here
      13 |         for_each_pci_dev(pdev) {
         |                          ^~~~
   include/linux/pci.h:546:80: note: expanded from macro 'for_each_pci_dev'
     546 | #define for_each_pci_dev(d) while ((d = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, d)) != NULL)
         |                                                                                ^
   drivers/video/screen_info_pci.c:10:2: note: remove the 'if' if its condition is always true
      10 |         if (!(res->flags & IORESOURCE_MEM))
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      11 |                 return NULL;
   drivers/video/screen_info_pci.c:8:22: note: initialize the variable 'pdev' to silence this warning
       8 |         struct pci_dev *pdev;
         |                             ^
         |                              = NULL
   1 warning generated.


vim +10 drivers/video/screen_info_pci.c

     5	
     6	static struct pci_dev *__screen_info_pci_dev(struct resource *res)
     7	{
     8		struct pci_dev *pdev;
     9	
  > 10		if (!(res->flags & IORESOURCE_MEM))
    11			return NULL;
    12	
    13		for_each_pci_dev(pdev) {
    14			const struct resource *r;
    15	
    16			if ((pdev->class >> 16) != PCI_BASE_CLASS_DISPLAY)
    17				continue;
    18	
    19			r = pci_find_resource(pdev, res);
    20			if (r)
    21				return pdev;
    22		}
    23	
    24		return NULL;
    25	}
    26
Thomas Zimmermann Feb. 5, 2024, 8:14 a.m. UTC | #4
Hi

Am 02.02.24 um 17:31 schrieb Sui Jingfeng:
> Hi,
> 
> 
> On 2024/2/2 19:58, Thomas Zimmermann wrote:
>> diff --git a/drivers/video/screen_info_pci.c 
>> b/drivers/video/screen_info_pci.c
>> new file mode 100644
>> index 0000000000000..d959a4c6ba3d5
>> --- /dev/null
>> +++ b/drivers/video/screen_info_pci.c
>> @@ -0,0 +1,52 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +
>> +#include <linux/pci.h>
>> +#include <linux/screen_info.h>
>> +
>> +static struct pci_dev *__screen_info_pci_dev(struct resource *res)
>> +{
>> +    struct pci_dev *pdev;
>> +
>> +    if (!(res->flags & IORESOURCE_MEM))
>> +        return NULL;
>> +
>> +    for_each_pci_dev(pdev) {
>> +        const struct resource *r;
>> +
>> +        if ((pdev->class >> 16) != PCI_BASE_CLASS_DISPLAY)
>> +            continue;
>> +
>> +        r = pci_find_resource(pdev, res);
>> +        if (r)
>> +            return pdev;
>> +    }
>> +
>> +    return NULL;
>> +}
> 
> 
> I recommend using the pci_get_base_class() or pci_get_class() helper 
> function at here,
> for example:

Good idea, I think I'll do that. Thanks!

Best regards
Thomas

> 
> 
> static struct pci_dev *__screen_info_pci_dev(struct resource *res)
> {
>      struct pci_dev *pdev;
> 
>      if (!(res->flags & IORESOURCE_MEM))
>          return NULL;
> 
>      while ((pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, pdev))) {
>          if (pci_find_resource(pdev, res))
>              return pdev;
>      }
> 
>      return NULL;
> }
> 
>
Thomas Zimmermann Feb. 5, 2024, 8:17 a.m. UTC | #5
Hi

Am 02.02.24 um 18:03 schrieb Sui Jingfeng:
> Hi,
> 
> 
> On 2024/2/2 19:58, Thomas Zimmermann wrote:
>> +
>> +/**
>> + * screen_info_pci_dev() - Return PCI parent device that contains 
>> screen_info's framebuffer
>> + * @si: the screen_info
>> + *
>> + * Returns:
>> + * The screen_info's parent device on success, or NULL otherwise.
>> + */
>> +struct pci_dev *screen_info_pci_dev(const struct screen_info *si)
>> +{
>> +    struct resource res[SCREEN_INFO_MAX_RESOURCES];
>> +    ssize_t i, numres;
>> +
>> +    numres = screen_info_resources(si, res, ARRAY_SIZE(res));
>> +    if (numres < 0)
>> +        return ERR_PTR(numres);
> 
> 
> Please return NULL at here, otherwise we have to use the IS_ERR or 
> IS_ERR_OR_NULL()
> in the caller function to check the returned value. Meanwhile, I noticed 
> that you
> didn't actually call IS_ERR() in the sysfb_parent_dev() function 
> (introduced by the
> 3/8 patch), so I think we probably should return NULL at here.
> 
> Please also consider that the comments of this function says that it 
> return NULL on
> the otherwise cases.

Right. The idea is to return NULL is there is no parent device. The 
errno pointer is for actual runtime problems. The doc comment is still 
incorrect and I think I need to review the callers of this function. 
Thanks for pointing this out.

Best regards
Thomas

> 
> 
>> +    for (i = 0; i < numres; ++i) {
>> +        struct pci_dev *pdev = __screen_info_pci_dev(&res[i]);
>> +
>> +        if (pdev)
>> +            return pdev;
>> +    }
>> +
>> +    return NULL;
>> +}
>> +EXPORT_SYMBOL(screen_info_pci_dev);
Sui Jingfeng Feb. 5, 2024, 10:05 a.m. UTC | #6
Hi,

On 2024/2/5 16:17, Thomas Zimmermann wrote:
> Hi
>
> Am 02.02.24 um 18:03 schrieb Sui Jingfeng:
>> Hi,
>>
>>
>> On 2024/2/2 19:58, Thomas Zimmermann wrote:
>>> +
>>> +/**
>>> + * screen_info_pci_dev() - Return PCI parent device that contains 
>>> screen_info's framebuffer
>>> + * @si: the screen_info
>>> + *
>>> + * Returns:
>>> + * The screen_info's parent device on success, or NULL otherwise.
>>> + */
>>> +struct pci_dev *screen_info_pci_dev(const struct screen_info *si)
>>> +{
>>> +    struct resource res[SCREEN_INFO_MAX_RESOURCES];
>>> +    ssize_t i, numres;
>>> +
>>> +    numres = screen_info_resources(si, res, ARRAY_SIZE(res));
>>> +    if (numres < 0)
>>> +        return ERR_PTR(numres);
>>
>>
>> Please return NULL at here, otherwise we have to use the IS_ERR or 
>> IS_ERR_OR_NULL()
>> in the caller function to check the returned value. Meanwhile, I 
>> noticed that you
>> didn't actually call IS_ERR() in the sysfb_parent_dev() function 
>> (introduced by the
>> 3/8 patch), so I think we probably should return NULL at here.
>>
>> Please also consider that the comments of this function says that it 
>> return NULL on
>> the otherwise cases.
>
> Right. The idea is to return NULL is there is no parent device. 


return NULL is more easier and clear, it stand for "None" or "don't exist".
There is another reason that I want to tell you:

Some systems which don't have a good UEFI firmware support for uncommon GPUs.
the word "uncommon" means "not very popular GPU" or "extremely new GPU" or
"just refer to the GPUs that UEFI firmware don't know(recognize) about"

On such cases, there is no firmware framebuffer support. I means it is possible
that screen_info_resources() return -EINVAL because of not support yet. Then,
the screen_info_pci_dev(si) returns ERR_PTR(-EINVAL) and sysfb_pci_dev_is_enabled()
will take this error code as a pointer and de-reference it, cause the following
problem:

And even the x86-64 motherboard will not likely support all GPU(for example the one
with a old UEFI BIOS). And for an example, The intel Xe is the "extremely new GPU".


[    5.031966] CPU 4 Unable to handle kernel paging request at virtual 
address 000000000000081a, era == 900000000329b448, ra == 900000000329b440
[    5.044587] Oops[#1]:
[    5.046837] CPU: 4 PID: 1 Comm: swapper/0 Not tainted 6.8.0-rc1+ #7
[    5.053062] Hardware name: Loongson 
Loongson-3A6000-HV-7A2000-XA61200/Loongson-3A6000-HV-7A2000-XA61200, 
BIOS Loongson-UDK2018-V4.0.05636-stable202311 12/
[    5.066803] pc 900000000329b448 ra 900000000329b440 tp 
90000001000d0000 sp 90000001000d3d40
[    5.075100] a0 ffffffffffffffea a1 90000001000d3c38 a2 
0000000000000003 a3 9000000003867ce8
[    5.083398] a4 9000000003867ce0 a5 90000001000d3a80 a6 
0000000000000001 a7 0000000000000001
[    5.091695] t0 ac81f55e34713962 t1 ac81f55e34713962 t2 
0000000000000000 t3 0000000000000001
[    5.099992] t4 0000000000000004 t5 0000000000000000 t6 
0000000000000030 t7 0000000000000000
[    5.108290] t8 00000000000070b1 u0 0000000000000000 s9 
0000000000000008 s0 9000000003d58b48
[    5.116587] s1 9000000003c0b4a8 s2 9000000003787000 s3 
9000000003778000 s4 90000000032c0578
[    5.124884] s5 ffffffffffffffea s6 90000000032c0560 s7 
90000000032df900 s8 ffffffffccccc000
[    5.133182]    ra: 900000000329b440 sysfb_init+0x80/0x1f0
[    5.138545]   ERA: 900000000329b448 sysfb_init+0x88/0x1f0
[    5.143905]  CRMD: 000000b0 (PLV0 -IE -DA +PG DACF=CC DACM=CC -WE)
[    5.150048]  PRMD: 00000004 (PPLV0 +PIE -PWE)
[    5.154373]  EUEN: 00000000 (-FPE -SXE -ASXE -BTE)
[    5.159131]  ECFG: 00071c1c (LIE=2-4,10-12 VS=7)
[    5.163717] ESTAT: 00010000 [PIL] (IS= ECode=1 EsubCode=0)
[    5.169164]  BADV: 000000000000081a
[    5.172623]  PRID: 0014d000 (Loongson-64bit, Loongson-3A6000-HV)
[    5.178587] Modules linked in:
[    5.181614] Process swapper/0 (pid: 1, threadinfo=(____ptrval____), 
task=(____ptrval____))
[    5.189827] Stack : 0000000000000000 0000000000000000 
0000000000000000 0000000000000000
[    5.197782]         0000000000000000 ac81f55e34713962 
90000000032c0000 9000000003778000
[    5.205736]         90000000032c0578 0000000000000000 
900000000329b3c0 9000000003c54000
[    5.213691]         90000001000d3db8 9000000002260154 
0000000000000006 0000000000000000
[    5.221645]         0000000000000000 0000000000000000 
0000000000000000 0000000000000000
[    5.229599]         0000000000000000 0000000000000000 
0000000000000000 ac81f55e34713962
[    5.237553]         90000000037468f8 90000000037468f8 
90000000032c0578 90000000036a7658
[    5.245508]         0000000000000006 9000000100041e00 
0000000000000a55 9000000003260ff4
[    5.251549] ata3: SATA link down (SStatus 0 SControl 300)
[    5.253463]         0000000000000000 90000000032600b0 
0000000000000000 0000000000000000
[    5.266777]         0000000000000000 0000000000000000 
0000000000000000 0000000000000000
[    5.274731]         ...
[    5.277154] Call Trace:
[    5.277155] [<900000000329b448>] sysfb_init+0x88/0x1f0
[    5.284678] [<9000000002260154>] do_one_initcall+0x78/0x1cc
[    5.290213] [<9000000003260ff4>] kernel_init_freeable+0x228/0x298
[    5.296267] [<900000000324d104>] kernel_init+0x20/0x110
[    5.301455] [<90000000022611e8>] ret_from_kernel_thread+0xc/0xa4
[    5.307421]
[    5.308892] Code: 561667fe  0015009c  40007080 <2408308c> 29403860  
02c2e09b  0040818c  6400180c  1a007d45
[    5.318579]
[    5.320053] ---[ end trace 0000000000000000 ]---
[    5.324640] Kernel panic - not syncing: Attempted to kill init! 
exitcode=0x0000000b
[    5.332247] Kernel relocated by 0x2040000
[    5.336226]  .text @ 0x9000000002240000
[    5.340031]  .data @ 0x90000000032f0000
[    5.343835]  .bss  @ 0x9000000003c3f200
[    5.347640] ---[ end Kernel panic - not syncing: Attempted to kill 
init! exitcode=0x0000000b ]---


> Best regards
> Thomas
>
Thomas Zimmermann Feb. 5, 2024, 12:32 p.m. UTC | #7
Hi

Am 05.02.24 um 11:05 schrieb Sui Jingfeng:
> Hi,
> 
> On 2024/2/5 16:17, Thomas Zimmermann wrote:
>> Hi
>>
>> Am 02.02.24 um 18:03 schrieb Sui Jingfeng:
>>> Hi,
>>>
>>>
>>> On 2024/2/2 19:58, Thomas Zimmermann wrote:
>>>> +
>>>> +/**
>>>> + * screen_info_pci_dev() - Return PCI parent device that contains 
>>>> screen_info's framebuffer
>>>> + * @si: the screen_info
>>>> + *
>>>> + * Returns:
>>>> + * The screen_info's parent device on success, or NULL otherwise.
>>>> + */
>>>> +struct pci_dev *screen_info_pci_dev(const struct screen_info *si)
>>>> +{
>>>> +    struct resource res[SCREEN_INFO_MAX_RESOURCES];
>>>> +    ssize_t i, numres;
>>>> +
>>>> +    numres = screen_info_resources(si, res, ARRAY_SIZE(res));
>>>> +    if (numres < 0)
>>>> +        return ERR_PTR(numres);
>>>
>>>
>>> Please return NULL at here, otherwise we have to use the IS_ERR or 
>>> IS_ERR_OR_NULL()
>>> in the caller function to check the returned value. Meanwhile, I 
>>> noticed that you
>>> didn't actually call IS_ERR() in the sysfb_parent_dev() function 
>>> (introduced by the
>>> 3/8 patch), so I think we probably should return NULL at here.
>>>
>>> Please also consider that the comments of this function says that it 
>>> return NULL on
>>> the otherwise cases.
>>
>> Right. The idea is to return NULL is there is no parent device. 
> 
> 
> return NULL is more easier and clear, it stand for "None" or "don't exist".
> There is another reason that I want to tell you:
> 
> Some systems which don't have a good UEFI firmware support for uncommon 
> GPUs.
> the word "uncommon" means "not very popular GPU" or "extremely new GPU" or
> "just refer to the GPUs that UEFI firmware don't know(recognize) about"
> 
> On such cases, there is no firmware framebuffer support. I means it is 
> possible
> that screen_info_resources() return -EINVAL because of not support yet. 
> Then,
> the screen_info_pci_dev(si) returns ERR_PTR(-EINVAL) and 
> sysfb_pci_dev_is_enabled()
> will take this error code as a pointer and de-reference it, cause the 
> following
> problem:

Right, that's part of the bug you already pointed out. As I said, I need 
to review the callers of screen_info_pci_dev() and fix them.

But returning an errno pointer is useful in cases where a possible 
parent device would have been detected, but something did not work out. 
For example, screen_info_resources() does not support all VIDEO_TYPE_ 
constants. In such a case, it's better to tell the caller about the 
problem than to silently return NULL.

Best regards
Thomas

> 
> And even the x86-64 motherboard will not likely support all GPU(for 
> example the one
> with a old UEFI BIOS). And for an example, The intel Xe is the 
> "extremely new GPU".
> 
> 
> [    5.031966] CPU 4 Unable to handle kernel paging request at virtual 
> address 000000000000081a, era == 900000000329b448, ra == 900000000329b440
> [    5.044587] Oops[#1]:
> [    5.046837] CPU: 4 PID: 1 Comm: swapper/0 Not tainted 6.8.0-rc1+ #7
> [    5.053062] Hardware name: Loongson 
> Loongson-3A6000-HV-7A2000-XA61200/Loongson-3A6000-HV-7A2000-XA61200, 
> BIOS Loongson-UDK2018-V4.0.05636-stable202311 12/
> [    5.066803] pc 900000000329b448 ra 900000000329b440 tp 
> 90000001000d0000 sp 90000001000d3d40
> [    5.075100] a0 ffffffffffffffea a1 90000001000d3c38 a2 
> 0000000000000003 a3 9000000003867ce8
> [    5.083398] a4 9000000003867ce0 a5 90000001000d3a80 a6 
> 0000000000000001 a7 0000000000000001
> [    5.091695] t0 ac81f55e34713962 t1 ac81f55e34713962 t2 
> 0000000000000000 t3 0000000000000001
> [    5.099992] t4 0000000000000004 t5 0000000000000000 t6 
> 0000000000000030 t7 0000000000000000
> [    5.108290] t8 00000000000070b1 u0 0000000000000000 s9 
> 0000000000000008 s0 9000000003d58b48
> [    5.116587] s1 9000000003c0b4a8 s2 9000000003787000 s3 
> 9000000003778000 s4 90000000032c0578
> [    5.124884] s5 ffffffffffffffea s6 90000000032c0560 s7 
> 90000000032df900 s8 ffffffffccccc000
> [    5.133182]    ra: 900000000329b440 sysfb_init+0x80/0x1f0
> [    5.138545]   ERA: 900000000329b448 sysfb_init+0x88/0x1f0
> [    5.143905]  CRMD: 000000b0 (PLV0 -IE -DA +PG DACF=CC DACM=CC -WE)
> [    5.150048]  PRMD: 00000004 (PPLV0 +PIE -PWE)
> [    5.154373]  EUEN: 00000000 (-FPE -SXE -ASXE -BTE)
> [    5.159131]  ECFG: 00071c1c (LIE=2-4,10-12 VS=7)
> [    5.163717] ESTAT: 00010000 [PIL] (IS= ECode=1 EsubCode=0)
> [    5.169164]  BADV: 000000000000081a
> [    5.172623]  PRID: 0014d000 (Loongson-64bit, Loongson-3A6000-HV)
> [    5.178587] Modules linked in:
> [    5.181614] Process swapper/0 (pid: 1, threadinfo=(____ptrval____), 
> task=(____ptrval____))
> [    5.189827] Stack : 0000000000000000 0000000000000000 
> 0000000000000000 0000000000000000
> [    5.197782]         0000000000000000 ac81f55e34713962 
> 90000000032c0000 9000000003778000
> [    5.205736]         90000000032c0578 0000000000000000 
> 900000000329b3c0 9000000003c54000
> [    5.213691]         90000001000d3db8 9000000002260154 
> 0000000000000006 0000000000000000
> [    5.221645]         0000000000000000 0000000000000000 
> 0000000000000000 0000000000000000
> [    5.229599]         0000000000000000 0000000000000000 
> 0000000000000000 ac81f55e34713962
> [    5.237553]         90000000037468f8 90000000037468f8 
> 90000000032c0578 90000000036a7658
> [    5.245508]         0000000000000006 9000000100041e00 
> 0000000000000a55 9000000003260ff4
> [    5.251549] ata3: SATA link down (SStatus 0 SControl 300)
> [    5.253463]         0000000000000000 90000000032600b0 
> 0000000000000000 0000000000000000
> [    5.266777]         0000000000000000 0000000000000000 
> 0000000000000000 0000000000000000
> [    5.274731]         ...
> [    5.277154] Call Trace:
> [    5.277155] [<900000000329b448>] sysfb_init+0x88/0x1f0
> [    5.284678] [<9000000002260154>] do_one_initcall+0x78/0x1cc
> [    5.290213] [<9000000003260ff4>] kernel_init_freeable+0x228/0x298
> [    5.296267] [<900000000324d104>] kernel_init+0x20/0x110
> [    5.301455] [<90000000022611e8>] ret_from_kernel_thread+0xc/0xa4
> [    5.307421]
> [    5.308892] Code: 561667fe  0015009c  40007080 <2408308c> 29403860 
> 02c2e09b  0040818c  6400180c  1a007d45
> [    5.318579]
> [    5.320053] ---[ end trace 0000000000000000 ]---
> [    5.324640] Kernel panic - not syncing: Attempted to kill init! 
> exitcode=0x0000000b
> [    5.332247] Kernel relocated by 0x2040000
> [    5.336226]  .text @ 0x9000000002240000
> [    5.340031]  .data @ 0x90000000032f0000
> [    5.343835]  .bss  @ 0x9000000003c3f200
> [    5.347640] ---[ end Kernel panic - not syncing: Attempted to kill 
> init! exitcode=0x0000000b ]---
> 
> 
>> Best regards
>> Thomas
>>
>
diff mbox series

Patch

diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 117cbdbb58c2c..ffbac4387c670 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -8,6 +8,7 @@  obj-$(CONFIG_VIDEO)               += cmdline.o nomodeset.o
 obj-$(CONFIG_HDMI)                += hdmi.o
 
 screen_info-y			  := screen_info_generic.o
+screen_info-$(CONFIG_PCI)         += screen_info_pci.o
 
 obj-$(CONFIG_VT)		  += console/
 obj-$(CONFIG_FB_STI)		  += console/
diff --git a/drivers/video/screen_info_pci.c b/drivers/video/screen_info_pci.c
new file mode 100644
index 0000000000000..d959a4c6ba3d5
--- /dev/null
+++ b/drivers/video/screen_info_pci.c
@@ -0,0 +1,52 @@ 
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/pci.h>
+#include <linux/screen_info.h>
+
+static struct pci_dev *__screen_info_pci_dev(struct resource *res)
+{
+	struct pci_dev *pdev;
+
+	if (!(res->flags & IORESOURCE_MEM))
+		return NULL;
+
+	for_each_pci_dev(pdev) {
+		const struct resource *r;
+
+		if ((pdev->class >> 16) != PCI_BASE_CLASS_DISPLAY)
+			continue;
+
+		r = pci_find_resource(pdev, res);
+		if (r)
+			return pdev;
+	}
+
+	return NULL;
+}
+
+/**
+ * screen_info_pci_dev() - Return PCI parent device that contains screen_info's framebuffer
+ * @si: the screen_info
+ *
+ * Returns:
+ * The screen_info's parent device on success, or NULL otherwise.
+ */
+struct pci_dev *screen_info_pci_dev(const struct screen_info *si)
+{
+	struct resource res[SCREEN_INFO_MAX_RESOURCES];
+	ssize_t i, numres;
+
+	numres = screen_info_resources(si, res, ARRAY_SIZE(res));
+	if (numres < 0)
+		return ERR_PTR(numres);
+
+	for (i = 0; i < numres; ++i) {
+		struct pci_dev *pdev = __screen_info_pci_dev(&res[i]);
+
+		if (pdev)
+			return pdev;
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL(screen_info_pci_dev);
diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h
index e7a02c5609d12..0eae08e3c6f90 100644
--- a/include/linux/screen_info.h
+++ b/include/linux/screen_info.h
@@ -9,6 +9,7 @@ 
  */
 #define SCREEN_INFO_MAX_RESOURCES	3
 
+struct pci_dev;
 struct resource;
 
 static inline bool __screen_info_has_lfb(unsigned int type)
@@ -104,6 +105,15 @@  static inline unsigned int screen_info_video_type(const struct screen_info *si)
 
 ssize_t screen_info_resources(const struct screen_info *si, struct resource *r, size_t num);
 
+#if defined(CONFIG_PCI)
+struct pci_dev *screen_info_pci_dev(const struct screen_info *si);
+#else
+static inline struct pci_dev *screen_info_pci_dev(const struct screen_info *si)
+{
+	return NULL;
+}
+#endif
+
 extern struct screen_info screen_info;
 
 #endif /* _SCREEN_INFO_H */