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

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 412c8f7de011 ("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: Lukas Wunner <lukas@wunner.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/575885fd440c2b13c3f19ddf44360cfbbff35f50.1464685538.git.lukas@wunner.de

authored by

Lukas Wunner and committed by
Daniel Vetter
b00e5334 d1e372c4

+33 -28
+1 -9
drivers/gpu/drm/i915/i915_drv.c
··· 35 35 #include "i915_trace.h" 36 36 #include "intel_drv.h" 37 37 38 - #include <linux/apple-gmux.h> 39 38 #include <linux/console.h> 40 39 #include <linux/module.h> 41 40 #include <linux/pm_runtime.h> 42 - #include <linux/vgaarb.h> 43 41 #include <linux/vga_switcheroo.h> 44 42 #include <drm/drm_crtc_helper.h> 45 43 ··· 1023 1025 if (PCI_FUNC(pdev->devfn)) 1024 1026 return -ENODEV; 1025 1027 1026 - /* 1027 - * apple-gmux is needed on dual GPU MacBook Pro 1028 - * to probe the panel if we're the inactive GPU. 1029 - */ 1030 - if (IS_ENABLED(CONFIG_VGA_ARB) && IS_ENABLED(CONFIG_VGA_SWITCHEROO) && 1031 - apple_gmux_present() && pdev != vga_default_device() && 1032 - !vga_switcheroo_handler_flags()) 1028 + if (vga_switcheroo_client_probe_defer(pdev)) 1033 1029 return -EPROBE_DEFER; 1034 1030 1035 1031 return drm_get_pci_dev(pdev, ent, &driver);
+1 -9
drivers/gpu/drm/nouveau/nouveau_drm.c
··· 22 22 * Authors: Ben Skeggs 23 23 */ 24 24 25 - #include <linux/apple-gmux.h> 26 25 #include <linux/console.h> 27 26 #include <linux/delay.h> 28 27 #include <linux/module.h> 29 28 #include <linux/pci.h> 30 29 #include <linux/pm_runtime.h> 31 - #include <linux/vgaarb.h> 32 30 #include <linux/vga_switcheroo.h> 33 31 34 32 #include "drmP.h" ··· 313 315 bool boot = false; 314 316 int ret; 315 317 316 - /* 317 - * apple-gmux is needed on dual GPU MacBook Pro 318 - * to probe the panel if we're the inactive GPU. 319 - */ 320 - if (IS_ENABLED(CONFIG_VGA_ARB) && IS_ENABLED(CONFIG_VGA_SWITCHEROO) && 321 - apple_gmux_present() && pdev != vga_default_device() && 322 - !vga_switcheroo_handler_flags()) 318 + if (vga_switcheroo_client_probe_defer(pdev)) 323 319 return -EPROBE_DEFER; 324 320 325 321 /* remove conflicting drivers (vesafb, efifb etc) */
+1 -9
drivers/gpu/drm/radeon/radeon_drv.c
··· 34 34 #include "radeon_drv.h" 35 35 36 36 #include <drm/drm_pciids.h> 37 - #include <linux/apple-gmux.h> 38 37 #include <linux/console.h> 39 38 #include <linux/module.h> 40 39 #include <linux/pm_runtime.h> 41 - #include <linux/vgaarb.h> 42 40 #include <linux/vga_switcheroo.h> 43 41 #include <drm/drm_gem.h> 44 42 ··· 338 340 if (ret == -EPROBE_DEFER) 339 341 return ret; 340 342 341 - /* 342 - * apple-gmux is needed on dual GPU MacBook Pro 343 - * to probe the panel if we're the inactive GPU. 344 - */ 345 - if (IS_ENABLED(CONFIG_VGA_ARB) && IS_ENABLED(CONFIG_VGA_SWITCHEROO) && 346 - apple_gmux_present() && pdev != vga_default_device() && 347 - !vga_switcheroo_handler_flags()) 343 + if (vga_switcheroo_client_probe_defer(pdev)) 348 344 return -EPROBE_DEFER; 349 345 350 346 /* Get rid of things like offb */
+28 -1
drivers/gpu/vga/vga_switcheroo.c
··· 30 30 31 31 #define pr_fmt(fmt) "vga_switcheroo: " fmt 32 32 33 + #include <linux/apple-gmux.h> 33 34 #include <linux/console.h> 34 35 #include <linux/debugfs.h> 35 36 #include <linux/fb.h> ··· 309 308 * 310 309 * Register vga client (GPU). Enable vga_switcheroo if another GPU and a 311 310 * handler have already registered. The power state of the client is assumed 312 - * to be ON. 311 + * to be ON. Beforehand, vga_switcheroo_client_probe_defer() shall be called 312 + * to ensure that all prerequisites are met. 313 313 * 314 314 * Return: 0 on success, -ENOMEM on memory allocation error. 315 315 */ ··· 376 374 return client; 377 375 return NULL; 378 376 } 377 + 378 + /** 379 + * vga_switcheroo_client_probe_defer() - whether to defer probing a given client 380 + * @pdev: client pci device 381 + * 382 + * Determine whether any prerequisites are not fulfilled to probe a given 383 + * client. Drivers shall invoke this early on in their ->probe callback 384 + * and return %-EPROBE_DEFER if it evaluates to %true. Thou shalt not 385 + * register the client ere thou hast called this. 386 + * 387 + * Return: %true if probing should be deferred, otherwise %false. 388 + */ 389 + bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev) 390 + { 391 + /* 392 + * apple-gmux is needed on pre-retina MacBook Pro 393 + * to probe the panel if pdev is the inactive GPU. 394 + */ 395 + if (apple_gmux_present() && pdev != vga_default_device() && 396 + !vgasr_priv.handler_flags) 397 + return true; 398 + 399 + return false; 400 + } 401 + EXPORT_SYMBOL(vga_switcheroo_client_probe_defer); 379 402 380 403 /** 381 404 * vga_switcheroo_get_client_state() - obtain power state of a given client
+2
include/linux/vga_switcheroo.h
··· 165 165 166 166 int vga_switcheroo_process_delayed_switch(void); 167 167 168 + bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev); 168 169 enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev); 169 170 170 171 void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic); ··· 189 188 static inline int vga_switcheroo_lock_ddc(struct pci_dev *pdev) { return -ENODEV; } 190 189 static inline int vga_switcheroo_unlock_ddc(struct pci_dev *pdev) { return -ENODEV; } 191 190 static inline int vga_switcheroo_process_delayed_switch(void) { return 0; } 191 + static inline bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev) { return false; } 192 192 static inline enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev) { return VGA_SWITCHEROO_ON; } 193 193 194 194 static inline void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic) {}