From patchwork Fri Jun 30 10:57:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sui Jingfeng X-Patchwork-Id: 13298016 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BE0EAC001DF for ; Fri, 30 Jun 2023 10:58:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230013AbjF3K6S (ORCPT ); Fri, 30 Jun 2023 06:58:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46490 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232593AbjF3K6F (ORCPT ); Fri, 30 Jun 2023 06:58:05 -0400 Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id C34093AB9; Fri, 30 Jun 2023 03:58:02 -0700 (PDT) Received: from loongson.cn (unknown [10.20.42.43]) by gateway (Coremail) with SMTP id _____8CxqMU5tZ5kpEQEAA--.6977S3; Fri, 30 Jun 2023 18:58:01 +0800 (CST) Received: from openarena.loongson.cn (unknown [10.20.42.43]) by localhost.localdomain (Coremail) with SMTP id AQAAf8DxJ801tZ5k5GETAA--.63992S4; Fri, 30 Jun 2023 18:57:58 +0800 (CST) From: Sui Jingfeng To: Alex Deucher , David Airlie , Daniel Vetter , Thomas Zimmermann , Maxime Ripard , Jani Nikula Cc: dri-devel@lists.freedesktop.org, amd-gfx@lists.freedesktop.org, linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, nouveau@lists.freedesktop.org, linux-pci@vger.kernel.org, kvm@vger.kernel.org, linux-fbdev@vger.kernel.org, Christian Konig , Pan Xinhui , Joonas Lahtinen , Rodrigo Vivi , Tvrtko Ursulin , Ben Skeggs , Karol Herbst , Lyude Paul , Bjorn Helgaas , Alex Williamson , Maarten Lankhorst , Hawking Zhang , Mario Limonciello , Lijo Lazar , YiPeng Chai , Bokun Zhang , Likun Gao , Ville Syrjala , Jason Gunthorpe , Kevin Tian , Cornelia Huck , Yishai Hadas , Abhishek Sahu , Yi Liu Subject: [PATCH v1 2/4] PCI/VGA: Improve the default VGA device selection Date: Fri, 30 Jun 2023 18:57:55 +0800 Message-Id: <20230630105757.141582-3-suijingfeng@loongson.cn> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230630105757.141582-1-suijingfeng@loongson.cn> References: <20230630105757.141582-1-suijingfeng@loongson.cn> MIME-Version: 1.0 X-CM-TRANSID: AQAAf8DxJ801tZ5k5GETAA--.63992S4 X-CM-SenderInfo: xvxlyxpqjiv03j6o00pqjv00gofq/ X-Coremail-Antispam: 1Uk129KBj93XoW3CryrXF4DKr13CrWrJw4DJrc_yoWDZr1fpF 4rGF98AryxuF4I9w47Za48AFyYv3y2vayrGrW7Aw1Yga45ArWFqF90yFy5tryxJFZrCF13 tr9rKFW7uF1jvFcCm3ZEXasCq-sJn29KB7ZKAUJUUUUP529EdanIXcx71UUUUU7KY7ZEXa sCq-sGcSsGvfJ3Ic02F40EFcxC0VAKzVAqx4xG6I80ebIjqfuFe4nvWSU5nxnvy29KBjDU 0xBIdaVrnRJUUUBqb4IE77IF4wAFF20E14v26r1j6r4UM7CY07I20VC2zVCF04k26cxKx2 IYs7xG6rWj6s0DM7CIcVAFz4kK6r1Y6r17M28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48v e4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_Xr0_Ar1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI 0_Cr0_Gr1UM28EF7xvwVC2z280aVAFwI0_Gr1j6F4UJwA2z4x0Y4vEx4A2jsIEc7CjxVAF wI0_Cr1j6rxdM2kKe7AKxVWUtVW8ZwAS0I0E0xvYzxvE52x082IY62kv0487Mc804VCY07 AIYIkI8VC2zVCFFI0UMc02F40EFcxC0VAKzVAqx4xG6I80ewAv7VC0I7IYx2IY67AKxVWU tVWrXwAv7VC2z280aVAFwI0_Gr0_Cr1lOx8S6xCaFVCjc4AY6r1j6r4UM4x0Y48IcxkI7V AKI48JMxkF7I0En4kS14v26r4a6rW5MxAIw28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY 6r1j6r4UMxCIbckI1I0E14v26r1q6r43MI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2IqxVCjr7 xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVWrXVW8Jr1lIxkGc2Ij64vIr41lIxAIcVC0 I7IYx2IY67AKxVW5JVW7JwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Cr0_Gr1UMIIF0xvE42 xK8VAvwI8IcIk0rVWUJVWUCwCI42IY6I8E87Iv67AKxVW8JVWxJwCI42IY6I8E87Iv6xkF 7I0E14v26r4UJVWxJrUvcSsGvfC2KfnxnUUI43ZEXa7IUeVpB3UUUUU== Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org Currently, the default VGA device selection is not perfect. Potential problems are: 1) This function is a no-op on non-x86 architectures. 2) It does not take the PCI Bar may get relocated into consideration. 3) It is not effective for the PCI device without a dedicated VRAM Bar. 4) It is device-agnostic, thus it has to waste the effort to iterate all of the PCI Bar to find the VRAM aperture. 5) It has invented lots of methods to determine which one is the default boot device on a multiple video card coexistence system. But this is still a policy because it doesn't give the user a choice to override. With the observation that device drivers or video aperture helpers may have better knowledge about which PCI bar contains the firmware FB, This patch tries to solve the above problems by introducing a function callback to the vga_client_register() function interface. DRM device drivers for the PCI device need to register the is_boot_device() function callback during the driver loading time. Once the driver binds the device successfully, VRAARB will call back to the driver. This gives the device drivers a chance to provide accurate boot device identification. Which in turn unlock the abitration service to non-x86 architectures. A device driver can also pass a NULL pointer to the keep the original behavior. This patch is to introduce the mechanism only, while the implementation is left to the authors of various device driver. Also honor the comment: "Clients have two callback mechanisms they can use" Cc: Alex Deucher Cc: Christian Konig Cc: Pan Xinhui Cc: David Airlie Cc: Daniel Vetter Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: Tvrtko Ursulin Cc: Ben Skeggs Cc: Karol Herbst Cc: Lyude Paul Cc: Bjorn Helgaas Cc: Alex Williamson Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Cc: Hawking Zhang Cc: Mario Limonciello Cc: Lijo Lazar Cc: YiPeng Chai Cc: Bokun Zhang Cc: Likun Gao Cc: Ville Syrjala Cc: Jason Gunthorpe CC: Kevin Tian Cc: Cornelia Huck Cc: Yishai Hadas Cc: Abhishek Sahu Cc: Yi Liu Reviewed-by: Lyude Paul # nouveau Signed-off-by: Sui Jingfeng --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 +- drivers/gpu/drm/i915/display/intel_vga.c | 3 +-- drivers/gpu/drm/nouveau/nouveau_vga.c | 2 +- drivers/gpu/drm/radeon/radeon_device.c | 2 +- drivers/pci/vgaarb.c | 21 ++++++++++++++++++++- drivers/vfio/pci/vfio_pci_core.c | 2 +- include/linux/vgaarb.h | 8 +++++--- 7 files changed, 30 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index e25f085ee886..c5bdf6eff29e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4082,7 +4082,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, /* this will fail for cards that aren't VGA class devices, just * ignore it */ if ((adev->pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) - vga_client_register(adev->pdev, amdgpu_device_vga_set_decode); + vga_client_register(adev->pdev, amdgpu_device_vga_set_decode, NULL); px = amdgpu_device_supports_px(ddev); diff --git a/drivers/gpu/drm/i915/display/intel_vga.c b/drivers/gpu/drm/i915/display/intel_vga.c index 286a0bdd28c6..98d7d4dffe9f 100644 --- a/drivers/gpu/drm/i915/display/intel_vga.c +++ b/drivers/gpu/drm/i915/display/intel_vga.c @@ -115,7 +115,6 @@ intel_vga_set_decode(struct pci_dev *pdev, bool enable_decode) int intel_vga_register(struct drm_i915_private *i915) { - struct pci_dev *pdev = to_pci_dev(i915->drm.dev); int ret; @@ -127,7 +126,7 @@ int intel_vga_register(struct drm_i915_private *i915) * then we do not take part in VGA arbitration and the * vga_client_register() fails with -ENODEV. */ - ret = vga_client_register(pdev, intel_vga_set_decode); + ret = vga_client_register(pdev, intel_vga_set_decode, NULL); if (ret && ret != -ENODEV) return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c index f8bf0ec26844..162b4f4676c7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vga.c +++ b/drivers/gpu/drm/nouveau/nouveau_vga.c @@ -92,7 +92,7 @@ nouveau_vga_init(struct nouveau_drm *drm) return; pdev = to_pci_dev(dev->dev); - vga_client_register(pdev, nouveau_vga_set_decode); + vga_client_register(pdev, nouveau_vga_set_decode, NULL); /* don't register Thunderbolt eGPU with vga_switcheroo */ if (pci_is_thunderbolt_attached(pdev)) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index afbb3a80c0c6..71f2ff39d6a1 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1425,7 +1425,7 @@ int radeon_device_init(struct radeon_device *rdev, /* if we have > 1 VGA cards, then disable the radeon VGA resources */ /* this will fail for cards that aren't VGA class devices, just * ignore it */ - vga_client_register(rdev->pdev, radeon_vga_set_decode); + vga_client_register(rdev->pdev, radeon_vga_set_decode, NULL); if (rdev->flags & RADEON_IS_PX) runtime = true; diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c index 17bd1268c36a..99d6f1f9b789 100644 --- a/drivers/pci/vgaarb.c +++ b/drivers/pci/vgaarb.c @@ -53,6 +53,7 @@ struct vga_device { bool bridge_has_one_vga; bool is_firmware_default; /* device selected by firmware */ unsigned int (*set_decode)(struct pci_dev *pdev, bool decode); + bool (*is_boot_device)(struct pci_dev *pdev); }; static LIST_HEAD(vga_list); @@ -969,6 +970,10 @@ EXPORT_SYMBOL(vga_set_legacy_decoding); * @set_decode callback: If a client can disable its GPU VGA resource, it * will get a callback from this to set the encode/decode state. * + * @is_boot_device: callback to the device driver, query if a client is the + * default boot device, as the device driver typically has better knowledge + * if specific device is the boot device. But this callback is optional. + * * Rationale: we cannot disable VGA decode resources unconditionally, some * single GPU laptops seem to require ACPI or BIOS access to the VGA registers * to control things like backlights etc. Hopefully newer multi-GPU laptops do @@ -984,7 +989,8 @@ EXPORT_SYMBOL(vga_set_legacy_decoding); * Returns: 0 on success, -1 on failure */ int vga_client_register(struct pci_dev *pdev, - unsigned int (*set_decode)(struct pci_dev *pdev, bool decode)) + unsigned int (*set_decode)(struct pci_dev *pdev, bool decode), + bool (*is_boot_device)(struct pci_dev *pdev)) { int ret = -ENODEV; struct vga_device *vgadev; @@ -996,6 +1002,7 @@ int vga_client_register(struct pci_dev *pdev, goto bail; vgadev->set_decode = set_decode; + vgadev->is_boot_device = is_boot_device; ret = 0; bail: @@ -1521,6 +1528,18 @@ static int pci_notify(struct notifier_block *nb, unsigned long action, notify = vga_arbiter_add_pci_device(pdev); else if (action == BUS_NOTIFY_DEL_DEVICE) notify = vga_arbiter_del_pci_device(pdev); + else if (action == BUS_NOTIFY_BOUND_DRIVER) { + struct vga_device *vgadev = vgadev_find(pdev); + + if (vgadev && vgadev->is_boot_device) { + bool boot_dev = vgadev->is_boot_device(pdev); + + if (boot_dev) { + vgaarb_info(dev, "Overriding as boot device\n"); + vga_set_default_device(pdev); + } + } + } vgaarb_dbg(dev, "%s: action = %lu\n", __func__, action); diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c index a5ab416cf476..2a8873a330ba 100644 --- a/drivers/vfio/pci/vfio_pci_core.c +++ b/drivers/vfio/pci/vfio_pci_core.c @@ -2067,7 +2067,7 @@ static int vfio_pci_vga_init(struct vfio_pci_core_device *vdev) if (ret) return ret; - ret = vga_client_register(pdev, vfio_pci_set_decode); + ret = vga_client_register(pdev, vfio_pci_set_decode, NULL); if (ret) return ret; vga_set_legacy_decoding(pdev, vfio_pci_set_decode(pdev, false)); diff --git a/include/linux/vgaarb.h b/include/linux/vgaarb.h index 97129a1bbb7d..dfde5a6ba55a 100644 --- a/include/linux/vgaarb.h +++ b/include/linux/vgaarb.h @@ -33,7 +33,8 @@ struct pci_dev *vga_default_device(void); void vga_set_default_device(struct pci_dev *pdev); int vga_remove_vgacon(struct pci_dev *pdev); int vga_client_register(struct pci_dev *pdev, - unsigned int (*set_decode)(struct pci_dev *pdev, bool state)); + unsigned int (*set_decode)(struct pci_dev *pdev, bool state), + bool (*is_boot_device)(struct pci_dev *pdev)); #else /* CONFIG_VGA_ARB */ static inline void vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes) @@ -59,7 +60,8 @@ static inline int vga_remove_vgacon(struct pci_dev *pdev) return 0; } static inline int vga_client_register(struct pci_dev *pdev, - unsigned int (*set_decode)(struct pci_dev *pdev, bool state)) + unsigned int (*set_decode)(struct pci_dev *pdev, bool state), + bool (*is_boot_device)(struct pci_dev *pdev)) { return 0; } @@ -97,7 +99,7 @@ static inline int vga_get_uninterruptible(struct pci_dev *pdev, static inline void vga_client_unregister(struct pci_dev *pdev) { - vga_client_register(pdev, NULL); + vga_client_register(pdev, NULL, NULL); } #endif /* LINUX_VGA_H */