git: 21b556557e46 - main - linuxkpi: Fix `pci_upstream_bridge()` with DRM devices
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 13 Apr 2025 10:00:57 UTC
The branch main has been updated by dumbbell: URL: https://cgit.FreeBSD.org/src/commit/?id=21b556557e464701960c4a8b4dcc062cb3954ddc commit 21b556557e464701960c4a8b4dcc062cb3954ddc Author: Jean-Sébastien Pédron <dumbbell@FreeBSD.org> AuthorDate: 2025-03-03 23:48:20 +0000 Commit: Jean-Sébastien Pédron <dumbbell@FreeBSD.org> CommitDate: 2025-04-13 09:51:13 +0000 linuxkpi: Fix `pci_upstream_bridge()` with DRM devices In the case of DRM drivers, the passed device is a child of `vgapci`. We want to start the lookup from `vgapci`, so the parent of the passed `drmn`. We use the `isdrm` flag to determine if we are in this situation. This fixes an infinite loop with the amdgpu DRM driver that started to use this function in Linux 6.8: `pci_upstream_bridge()` was returning itself and the code in amdgpu was calling it again, hoping to get a device with a vendor that is not "ATI". Reviewed by: bz Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D49388 --- sys/compat/linuxkpi/common/include/linux/pci.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sys/compat/linuxkpi/common/include/linux/pci.h b/sys/compat/linuxkpi/common/include/linux/pci.h index afd6c827b3b4..e4e8e5c0abd1 100644 --- a/sys/compat/linuxkpi/common/include/linux/pci.h +++ b/sys/compat/linuxkpi/common/include/linux/pci.h @@ -523,7 +523,20 @@ pci_upstream_bridge(struct pci_dev *pdev) if (pdev == pdev->bus->self) { device_t bridge; - bridge = device_get_parent(pdev->dev.bsddev); + /* + * In the case of DRM drivers, the passed device is a child of + * `vgapci`. We want to start the lookup from `vgapci`, so the + * parent of the passed `drmn`. + * + * We can use the `isdrm` flag to determine this. + */ + bridge = pdev->dev.bsddev; + if (pdev->pdrv != NULL && pdev->pdrv->isdrm) + bridge = device_get_parent(bridge); + if (bridge == NULL) + goto done; + + bridge = device_get_parent(bridge); if (bridge == NULL) goto done; bridge = device_get_parent(bridge);