1 // SPDX-License-Identifier: GPL-2.0
4 #include <linux/printk.h>
5 #include <linux/screen_info.h>
6 #include <linux/string.h>
8 static struct pci_dev
*screen_info_lfb_pdev
;
9 static size_t screen_info_lfb_bar
;
10 static resource_size_t screen_info_lfb_offset
;
11 static struct resource screen_info_lfb_res
= DEFINE_RES_MEM(0, 0);
13 static bool __screen_info_relocation_is_valid(const struct screen_info
*si
, struct resource
*pr
)
15 u64 size
= __screen_info_lfb_size(si
, screen_info_video_type(si
));
17 if (screen_info_lfb_offset
> resource_size(pr
))
19 if (size
> resource_size(pr
))
21 if (resource_size(pr
) - size
< screen_info_lfb_offset
)
27 void screen_info_apply_fixups(void)
29 struct screen_info
*si
= &screen_info
;
31 if (screen_info_lfb_pdev
) {
32 struct resource
*pr
= &screen_info_lfb_pdev
->resource
[screen_info_lfb_bar
];
34 if (pr
->start
!= screen_info_lfb_res
.start
) {
35 if (__screen_info_relocation_is_valid(si
, pr
)) {
37 * Only update base if we have an actual
38 * relocation to a valid I/O range.
40 __screen_info_set_lfb_base(si
, pr
->start
+ screen_info_lfb_offset
);
41 pr_info("Relocating firmware framebuffer to offset %pa[d] within %pr\n",
42 &screen_info_lfb_offset
, pr
);
44 pr_warn("Invalid relocating, disabling firmware framebuffer\n");
50 static void screen_info_fixup_lfb(struct pci_dev
*pdev
)
53 struct resource res
[SCREEN_INFO_MAX_RESOURCES
];
56 const struct screen_info
*si
= &screen_info
;
58 if (screen_info_lfb_pdev
)
59 return; // already found
61 type
= screen_info_video_type(si
);
62 if (type
!= VIDEO_TYPE_EFI
)
63 return; // only applies to EFI
65 ret
= screen_info_resources(si
, res
, ARRAY_SIZE(res
));
70 for (i
= 0; i
< numres
; ++i
) {
71 struct resource
*r
= &res
[i
];
72 const struct resource
*pr
;
74 if (!(r
->flags
& IORESOURCE_MEM
))
76 pr
= pci_find_resource(pdev
, r
);
81 * We've found a PCI device with the framebuffer
82 * resource. Store away the parameters to track
83 * relocation of the framebuffer aperture.
85 screen_info_lfb_pdev
= pdev
;
86 screen_info_lfb_bar
= pr
- pdev
->resource
;
87 screen_info_lfb_offset
= r
->start
- pr
->start
;
88 memcpy(&screen_info_lfb_res
, r
, sizeof(screen_info_lfb_res
));
91 DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID
, PCI_ANY_ID
, PCI_BASE_CLASS_DISPLAY
, 16,
92 screen_info_fixup_lfb
);
94 static struct pci_dev
*__screen_info_pci_dev(struct resource
*res
)
96 struct pci_dev
*pdev
= NULL
;
97 const struct resource
*r
= NULL
;
99 if (!(res
->flags
& IORESOURCE_MEM
))
102 while (!r
&& (pdev
= pci_get_base_class(PCI_BASE_CLASS_DISPLAY
, pdev
))) {
103 r
= pci_find_resource(pdev
, res
);
110 * screen_info_pci_dev() - Return PCI parent device that contains screen_info's framebuffer
111 * @si: the screen_info
114 * The screen_info's parent device or NULL on success, or a pointer-encoded
115 * errno value otherwise. The value NULL is not an error. It signals that no
116 * PCI device has been found.
118 struct pci_dev
*screen_info_pci_dev(const struct screen_info
*si
)
120 struct resource res
[SCREEN_INFO_MAX_RESOURCES
];
123 numres
= screen_info_resources(si
, res
, ARRAY_SIZE(res
));
125 return ERR_PTR(numres
);
127 for (i
= 0; i
< numres
; ++i
) {
128 struct pci_dev
*pdev
= __screen_info_pci_dev(&res
[i
]);
136 EXPORT_SYMBOL(screen_info_pci_dev
);