Commit b00e5334 authored by Lukas Wunner's avatar Lukas Wunner Committed by Daniel Vetter

vga_switcheroo: Add helper for deferred probing

So far we've got one condition when DRM drivers need to defer probing
on a dual GPU system and it's coded separately into each of the relevant
drivers. As suggested by Daniel Vetter, deduplicate that code in the
drivers and move it to a new vga_switcheroo helper. This yields better
encapsulation of concepts and lets us add further checks in a central
place. (The existing check pertains to pre-retina MacBook Pros and an
additional check is expected to be needed for retinas.)

One might be tempted to check deferred probing conditions in
vga_switcheroo_register_client(), but this is usually called fairly late
during driver load. The GPU is fully brought up and ready for switching
at that point. On boot the ->probe hook is potentially called dozens of
times until it finally succeeds, and each time we'd repeat bringup and
teardown of the GPU, lengthening boot time considerably and cluttering
logfiles. A separate helper is therefore needed which can be called
right at the beginning of the ->probe hook.

Note that amdgpu currently does not call this helper as the AMD GPUs
built into MacBook Pros are only supported by radeon so far.

v2: This helper could eventually be used by audio clients as well,
    so rephrase kerneldoc to refer to "client" instead of "GPU"
    and move the single existing check in an if block specific
    to PCI_CLASS_DISPLAY_VGA devices. Move documentation on
    that check from kerneldoc to a comment. (Daniel Vetter)

v3: Mandate in kerneldoc that registration of client shall only
    happen after calling this helper. (Daniel Vetter)

v4: Rebase on 412c8f7d ("drm/radeon: Return -EPROBE_DEFER when
    amdkfd not loaded")

v5: Some Optimus GPUs use PCI_CLASS_DISPLAY_3D, make sure those are
    matched as well. (Emil Velikov)

v6: The if-condition referring to PCI_BASE_CLASS_DISPLAY may be
    considered a functional change. Move to a separate commit to
    keep this a pure refactoring change. (Emil Velikov, Jani Nikula)

Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Ben Skeggs <bskeggs@redhat.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarLukas Wunner <lukas@wunner.de>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/575885fd440c2b13c3f19ddf44360cfbbff35f50.1464685538.git.lukas@wunner.de
parent d1e372c4
...@@ -35,11 +35,9 @@ ...@@ -35,11 +35,9 @@
#include "i915_trace.h" #include "i915_trace.h"
#include "intel_drv.h" #include "intel_drv.h"
#include <linux/apple-gmux.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h> #include <linux/vga_switcheroo.h>
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
...@@ -1025,13 +1023,7 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1025,13 +1023,7 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (PCI_FUNC(pdev->devfn)) if (PCI_FUNC(pdev->devfn))
return -ENODEV; return -ENODEV;
/* if (vga_switcheroo_client_probe_defer(pdev))
* apple-gmux is needed on dual GPU MacBook Pro
* to probe the panel if we're the inactive GPU.
*/
if (IS_ENABLED(CONFIG_VGA_ARB) && IS_ENABLED(CONFIG_VGA_SWITCHEROO) &&
apple_gmux_present() && pdev != vga_default_device() &&
!vga_switcheroo_handler_flags())
return -EPROBE_DEFER; return -EPROBE_DEFER;
return drm_get_pci_dev(pdev, ent, &driver); return drm_get_pci_dev(pdev, ent, &driver);
......
...@@ -22,13 +22,11 @@ ...@@ -22,13 +22,11 @@
* Authors: Ben Skeggs * Authors: Ben Skeggs
*/ */
#include <linux/apple-gmux.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h> #include <linux/vga_switcheroo.h>
#include "drmP.h" #include "drmP.h"
...@@ -315,13 +313,7 @@ static int nouveau_drm_probe(struct pci_dev *pdev, ...@@ -315,13 +313,7 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
bool boot = false; bool boot = false;
int ret; int ret;
/* if (vga_switcheroo_client_probe_defer(pdev))
* apple-gmux is needed on dual GPU MacBook Pro
* to probe the panel if we're the inactive GPU.
*/
if (IS_ENABLED(CONFIG_VGA_ARB) && IS_ENABLED(CONFIG_VGA_SWITCHEROO) &&
apple_gmux_present() && pdev != vga_default_device() &&
!vga_switcheroo_handler_flags())
return -EPROBE_DEFER; return -EPROBE_DEFER;
/* remove conflicting drivers (vesafb, efifb etc) */ /* remove conflicting drivers (vesafb, efifb etc) */
......
...@@ -34,11 +34,9 @@ ...@@ -34,11 +34,9 @@
#include "radeon_drv.h" #include "radeon_drv.h"
#include <drm/drm_pciids.h> #include <drm/drm_pciids.h>
#include <linux/apple-gmux.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h> #include <linux/vga_switcheroo.h>
#include <drm/drm_gem.h> #include <drm/drm_gem.h>
...@@ -340,13 +338,7 @@ static int radeon_pci_probe(struct pci_dev *pdev, ...@@ -340,13 +338,7 @@ static int radeon_pci_probe(struct pci_dev *pdev,
if (ret == -EPROBE_DEFER) if (ret == -EPROBE_DEFER)
return ret; return ret;
/* if (vga_switcheroo_client_probe_defer(pdev))
* apple-gmux is needed on dual GPU MacBook Pro
* to probe the panel if we're the inactive GPU.
*/
if (IS_ENABLED(CONFIG_VGA_ARB) && IS_ENABLED(CONFIG_VGA_SWITCHEROO) &&
apple_gmux_present() && pdev != vga_default_device() &&
!vga_switcheroo_handler_flags())
return -EPROBE_DEFER; return -EPROBE_DEFER;
/* Get rid of things like offb */ /* Get rid of things like offb */
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#define pr_fmt(fmt) "vga_switcheroo: " fmt #define pr_fmt(fmt) "vga_switcheroo: " fmt
#include <linux/apple-gmux.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/fb.h> #include <linux/fb.h>
...@@ -308,7 +309,8 @@ static int register_client(struct pci_dev *pdev, ...@@ -308,7 +309,8 @@ static int register_client(struct pci_dev *pdev,
* *
* Register vga client (GPU). Enable vga_switcheroo if another GPU and a * Register vga client (GPU). Enable vga_switcheroo if another GPU and a
* handler have already registered. The power state of the client is assumed * handler have already registered. The power state of the client is assumed
* to be ON. * to be ON. Beforehand, vga_switcheroo_client_probe_defer() shall be called
* to ensure that all prerequisites are met.
* *
* Return: 0 on success, -ENOMEM on memory allocation error. * Return: 0 on success, -ENOMEM on memory allocation error.
*/ */
...@@ -375,6 +377,31 @@ find_active_client(struct list_head *head) ...@@ -375,6 +377,31 @@ find_active_client(struct list_head *head)
return NULL; return NULL;
} }
/**
* vga_switcheroo_client_probe_defer() - whether to defer probing a given client
* @pdev: client pci device
*
* Determine whether any prerequisites are not fulfilled to probe a given
* client. Drivers shall invoke this early on in their ->probe callback
* and return %-EPROBE_DEFER if it evaluates to %true. Thou shalt not
* register the client ere thou hast called this.
*
* Return: %true if probing should be deferred, otherwise %false.
*/
bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev)
{
/*
* apple-gmux is needed on pre-retina MacBook Pro
* to probe the panel if pdev is the inactive GPU.
*/
if (apple_gmux_present() && pdev != vga_default_device() &&
!vgasr_priv.handler_flags)
return true;
return false;
}
EXPORT_SYMBOL(vga_switcheroo_client_probe_defer);
/** /**
* vga_switcheroo_get_client_state() - obtain power state of a given client * vga_switcheroo_get_client_state() - obtain power state of a given client
* @pdev: client pci device * @pdev: client pci device
......
...@@ -165,6 +165,7 @@ int vga_switcheroo_unlock_ddc(struct pci_dev *pdev); ...@@ -165,6 +165,7 @@ int vga_switcheroo_unlock_ddc(struct pci_dev *pdev);
int vga_switcheroo_process_delayed_switch(void); int vga_switcheroo_process_delayed_switch(void);
bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev);
enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev); enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev);
void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic); void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic);
...@@ -188,6 +189,7 @@ static inline enum vga_switcheroo_handler_flags_t vga_switcheroo_handler_flags(v ...@@ -188,6 +189,7 @@ static inline enum vga_switcheroo_handler_flags_t vga_switcheroo_handler_flags(v
static inline int vga_switcheroo_lock_ddc(struct pci_dev *pdev) { return -ENODEV; } static inline int vga_switcheroo_lock_ddc(struct pci_dev *pdev) { return -ENODEV; }
static inline int vga_switcheroo_unlock_ddc(struct pci_dev *pdev) { return -ENODEV; } static inline int vga_switcheroo_unlock_ddc(struct pci_dev *pdev) { return -ENODEV; }
static inline int vga_switcheroo_process_delayed_switch(void) { return 0; } static inline int vga_switcheroo_process_delayed_switch(void) { return 0; }
static inline bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev) { return false; }
static inline enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev) { return VGA_SWITCHEROO_ON; } static inline enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev) { return VGA_SWITCHEROO_ON; }
static inline void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic) {} static inline void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic) {}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment