Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

firmware: google: framebuffer: Tie platform device to PCI hardware

Use the PCI device as parent of the system-framebuffer device instead
of the coreboot device. Prevents SIGBUS or SIGSEG after hot-unplug of
the PCI device while the framebuffer is active.

The simple-framebuffer device depends on the PCI hardware, so this
device needs to be its parent. The current coreboot parent is no
longer needed after the system-framebuffer device has been created.

On systems without PCI or if no PCI parent device could be found,
the platform device hangs on the platform bus directly.

The fix here is similar to code in sysfb, which contained that same
bug.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Tzung-Bi Shih <tzungbi@kernel.org>
Acked-by: Julius Werner <jwerner@chromium.org>
Link: https://patch.msgid.link/20260217155836.96267-5-tzimmermann@suse.de

+77 -5
+77 -5
drivers/firmware/google/framebuffer-coreboot.c
··· 13 13 #include <linux/kernel.h> 14 14 #include <linux/mm.h> 15 15 #include <linux/module.h> 16 + #include <linux/pci.h> 16 17 #include <linux/platform_data/simplefb.h> 17 18 #include <linux/platform_device.h> 18 19 #include <linux/sysfb.h> ··· 22 21 23 22 #define CB_TAG_FRAMEBUFFER 0x12 24 23 24 + #if defined(CONFIG_PCI) 25 + static bool framebuffer_pci_dev_is_enabled(struct pci_dev *pdev) 26 + { 27 + /* 28 + * TODO: Try to integrate this code into the PCI subsystem 29 + */ 30 + int ret; 31 + u16 command; 32 + 33 + ret = pci_read_config_word(pdev, PCI_COMMAND, &command); 34 + if (ret != PCIBIOS_SUCCESSFUL) 35 + return false; 36 + if (!(command & PCI_COMMAND_MEMORY)) 37 + return false; 38 + return true; 39 + } 40 + 41 + static struct pci_dev *framebuffer_parent_pci_dev(struct resource *res) 42 + { 43 + struct pci_dev *pdev = NULL; 44 + const struct resource *r = NULL; 45 + 46 + while (!r && (pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, pdev))) 47 + r = pci_find_resource(pdev, res); 48 + 49 + if (!r || !pdev) 50 + return NULL; /* not found; not an error */ 51 + 52 + if (!framebuffer_pci_dev_is_enabled(pdev)) { 53 + pci_dev_put(pdev); 54 + return ERR_PTR(-ENODEV); 55 + } 56 + 57 + return pdev; 58 + } 59 + #else 60 + static struct pci_dev *framebuffer_parent_pci_dev(struct resource *res) 61 + { 62 + return NULL; 63 + } 64 + #endif 65 + 66 + static struct device *framebuffer_parent_dev(struct resource *res) 67 + { 68 + struct pci_dev *pdev; 69 + 70 + pdev = framebuffer_parent_pci_dev(res); 71 + if (IS_ERR(pdev)) 72 + return ERR_CAST(pdev); 73 + else if (pdev) 74 + return &pdev->dev; 75 + 76 + return NULL; 77 + } 78 + 25 79 static const struct simplefb_format formats[] = SIMPLEFB_FORMATS; 26 80 27 81 static int framebuffer_probe(struct coreboot_device *dev) 28 82 { 29 83 int i; 30 84 struct lb_framebuffer *fb = &dev->framebuffer; 85 + struct device *parent; 31 86 struct platform_device *pdev; 32 87 struct resource res; 88 + int ret; 33 89 struct simplefb_platform_data pdata = { 34 90 .width = fb->x_resolution, 35 91 .height = fb->y_resolution, ··· 115 57 if (res.end <= res.start) 116 58 return -EINVAL; 117 59 60 + parent = framebuffer_parent_dev(&res); 61 + if (IS_ERR(parent)) 62 + return PTR_ERR(parent); 63 + 118 64 for (i = 0; i < ARRAY_SIZE(formats); ++i) { 119 65 if (fb->bits_per_pixel == formats[i].bits_per_pixel && 120 66 fb->red_mask_pos == formats[i].red.offset && ··· 129 67 fb->blue_mask_size == formats[i].blue.length) 130 68 pdata.format = formats[i].name; 131 69 } 132 - if (!pdata.format) 133 - return -ENODEV; 70 + if (!pdata.format) { 71 + ret = -ENODEV; 72 + goto out_put_device_parent; 73 + } 134 74 135 - pdev = platform_device_register_resndata(&dev->dev, 75 + pdev = platform_device_register_resndata(parent, 136 76 "simple-framebuffer", 0, 137 77 &res, 1, &pdata, 138 78 sizeof(pdata)); 139 - if (IS_ERR(pdev)) 79 + if (IS_ERR(pdev)) { 80 + ret = PTR_ERR(pdev); 140 81 pr_warn("coreboot: could not register framebuffer\n"); 82 + goto out_put_device_parent; 83 + } 141 84 142 - return PTR_ERR_OR_ZERO(pdev); 85 + ret = 0; 86 + 87 + out_put_device_parent: 88 + if (parent) 89 + put_device(parent); 90 + return ret; 143 91 } 144 92 145 93 static const struct coreboot_device_id framebuffer_ids[] = {