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

vga_switcheroo: Add handler flags infrastructure

Allow handlers to declare their capabilities and allow clients to
obtain that information. So far we have these use cases:

* If the handler is able to switch DDC separately, clients need to
probe EDID with drm_get_edid_switcheroo(). We should allow them
to detect a capable handler to ensure this function only gets
called when needed.

* Likewise if the handler is unable to switch AUX separately, the active
client needs to communicate link training parameters to the inactive
client, which may then skip the AUX handshake and set up its output
with these pre-calibrated values (DisplayPort specification v1.1a,
section 2.5.3.3). Clients need a way to recognize such a situation.

The flags for the radeon_atpx_handler and amdgpu_atpx_handler are
initially set to 0, this can later on be amended with
handler_flags |= VGA_SWITCHEROO_CAN_SWITCH_DDC;
when a ->switch_ddc callback is added.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115
Tested-by: Lukas Wunner <lukas@wunner.de>
[MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina 15"]
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Reviewed-by: Darren Hart <dvhart@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/2b0d93ed6e511ca09e95e45e0b35627f330fabce.1452525860.git.lukas@wunner.de

authored by

Lukas Wunner and committed by
Daniel Vetter
156d7d41 e87a52b3

+54 -7
+1
Documentation/DocBook/gpu.tmpl
··· 3422 3422 </sect1> 3423 3423 <sect1> 3424 3424 <title>Public constants</title> 3425 + !Finclude/linux/vga_switcheroo.h vga_switcheroo_handler_flags_t 3425 3426 !Finclude/linux/vga_switcheroo.h vga_switcheroo_client_id 3426 3427 !Finclude/linux/vga_switcheroo.h vga_switcheroo_state 3427 3428 </sect1>
+2 -1
drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
··· 552 552 void amdgpu_register_atpx_handler(void) 553 553 { 554 554 bool r; 555 + enum vga_switcheroo_handler_flags_t handler_flags = 0; 555 556 556 557 /* detect if we have any ATPX + 2 VGA in the system */ 557 558 r = amdgpu_atpx_detect(); 558 559 if (!r) 559 560 return; 560 561 561 - vga_switcheroo_register_handler(&amdgpu_atpx_handler); 562 + vga_switcheroo_register_handler(&amdgpu_atpx_handler, handler_flags); 562 563 } 563 564 564 565 /**
+1 -1
drivers/gpu/drm/nouveau/nouveau_acpi.c
··· 314 314 if (!r) 315 315 return; 316 316 317 - vga_switcheroo_register_handler(&nouveau_dsm_handler); 317 + vga_switcheroo_register_handler(&nouveau_dsm_handler, 0); 318 318 } 319 319 320 320 /* Must be called for Optimus models before the card can be turned off */
+2 -1
drivers/gpu/drm/radeon/radeon_atpx_handler.c
··· 551 551 void radeon_register_atpx_handler(void) 552 552 { 553 553 bool r; 554 + enum vga_switcheroo_handler_flags_t handler_flags = 0; 554 555 555 556 /* detect if we have any ATPX + 2 VGA in the system */ 556 557 r = radeon_atpx_detect(); 557 558 if (!r) 558 559 return; 559 560 560 - vga_switcheroo_register_handler(&radeon_atpx_handler); 561 + vga_switcheroo_register_handler(&radeon_atpx_handler, handler_flags); 561 562 } 562 563 563 564 /**
+21 -1
drivers/gpu/vga/vga_switcheroo.c
··· 126 126 * (counting only vga clients, not audio clients) 127 127 * @clients: list of registered clients 128 128 * @handler: registered handler 129 + * @handler_flags: flags of registered handler 129 130 * 130 131 * vga_switcheroo private data. Currently only one vga_switcheroo instance 131 132 * per system is supported. ··· 143 142 struct list_head clients; 144 143 145 144 const struct vga_switcheroo_handler *handler; 145 + enum vga_switcheroo_handler_flags_t handler_flags; 146 146 }; 147 147 148 148 #define ID_BIT_AUDIO 0x100 ··· 192 190 /** 193 191 * vga_switcheroo_register_handler() - register handler 194 192 * @handler: handler callbacks 193 + * @handler_flags: handler flags 195 194 * 196 195 * Register handler. Enable vga_switcheroo if two vga clients have already 197 196 * registered. 198 197 * 199 198 * Return: 0 on success, -EINVAL if a handler was already registered. 200 199 */ 201 - int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler) 200 + int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler, 201 + enum vga_switcheroo_handler_flags_t handler_flags) 202 202 { 203 203 mutex_lock(&vgasr_mutex); 204 204 if (vgasr_priv.handler) { ··· 209 205 } 210 206 211 207 vgasr_priv.handler = handler; 208 + vgasr_priv.handler_flags = handler_flags; 212 209 if (vga_switcheroo_ready()) { 213 210 pr_info("enabled\n"); 214 211 vga_switcheroo_enable(); ··· 227 222 void vga_switcheroo_unregister_handler(void) 228 223 { 229 224 mutex_lock(&vgasr_mutex); 225 + vgasr_priv.handler_flags = 0; 230 226 vgasr_priv.handler = NULL; 231 227 if (vgasr_priv.active) { 232 228 pr_info("disabled\n"); ··· 237 231 mutex_unlock(&vgasr_mutex); 238 232 } 239 233 EXPORT_SYMBOL(vga_switcheroo_unregister_handler); 234 + 235 + /** 236 + * vga_switcheroo_handler_flags() - obtain handler flags 237 + * 238 + * Helper for clients to obtain the handler flags bitmask. 239 + * 240 + * Return: Handler flags. A value of 0 means that no handler is registered 241 + * or that the handler has no special capabilities. 242 + */ 243 + enum vga_switcheroo_handler_flags_t vga_switcheroo_handler_flags(void) 244 + { 245 + return vgasr_priv.handler_flags; 246 + } 247 + EXPORT_SYMBOL(vga_switcheroo_handler_flags); 240 248 241 249 static int register_client(struct pci_dev *pdev, 242 250 const struct vga_switcheroo_client_ops *ops,
+1 -1
drivers/platform/x86/apple-gmux.c
··· 705 705 init_completion(&gmux_data->powerchange_done); 706 706 gmux_enable_interrupts(gmux_data); 707 707 708 - if (vga_switcheroo_register_handler(&gmux_handler)) { 708 + if (vga_switcheroo_register_handler(&gmux_handler, 0)) { 709 709 ret = -ENODEV; 710 710 goto err_register_handler; 711 711 }
+26 -2
include/linux/vga_switcheroo.h
··· 36 36 struct pci_dev; 37 37 38 38 /** 39 + * enum vga_switcheroo_handler_flags_t - handler flags bitmask 40 + * @VGA_SWITCHEROO_CAN_SWITCH_DDC: whether the handler is able to switch the 41 + * DDC lines separately. This signals to clients that they should call 42 + * drm_get_edid_switcheroo() to probe the EDID 43 + * @VGA_SWITCHEROO_NEEDS_EDP_CONFIG: whether the handler is unable to switch 44 + * the AUX channel separately. This signals to clients that the active 45 + * GPU needs to train the link and communicate the link parameters to the 46 + * inactive GPU (mediated by vga_switcheroo). The inactive GPU may then 47 + * skip the AUX handshake and set up its output with these pre-calibrated 48 + * values (DisplayPort specification v1.1a, section 2.5.3.3) 49 + * 50 + * Handler flags bitmask. Used by handlers to declare their capabilities upon 51 + * registering with vga_switcheroo. 52 + */ 53 + enum vga_switcheroo_handler_flags_t { 54 + VGA_SWITCHEROO_CAN_SWITCH_DDC = (1 << 0), 55 + VGA_SWITCHEROO_NEEDS_EDP_CONFIG = (1 << 1), 56 + }; 57 + 58 + /** 39 59 * enum vga_switcheroo_state - client power state 40 60 * @VGA_SWITCHEROO_OFF: off 41 61 * @VGA_SWITCHEROO_ON: on ··· 152 132 void vga_switcheroo_client_fb_set(struct pci_dev *dev, 153 133 struct fb_info *info); 154 134 155 - int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler); 135 + int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler, 136 + enum vga_switcheroo_handler_flags_t handler_flags); 156 137 void vga_switcheroo_unregister_handler(void); 138 + enum vga_switcheroo_handler_flags_t vga_switcheroo_handler_flags(void); 157 139 158 140 int vga_switcheroo_process_delayed_switch(void); 159 141 ··· 172 150 static inline int vga_switcheroo_register_client(struct pci_dev *dev, 173 151 const struct vga_switcheroo_client_ops *ops, bool driver_power_control) { return 0; } 174 152 static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct fb_info *info) {} 175 - static inline int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler) { return 0; } 153 + static inline int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler, 154 + enum vga_switcheroo_handler_flags_t handler_flags) { return 0; } 176 155 static inline int vga_switcheroo_register_audio_client(struct pci_dev *pdev, 177 156 const struct vga_switcheroo_client_ops *ops, 178 157 enum vga_switcheroo_client_id id) { return 0; } 179 158 static inline void vga_switcheroo_unregister_handler(void) {} 159 + static inline enum vga_switcheroo_handler_flags_t vga_switcheroo_handler_flags(void) { return 0; } 180 160 static inline int vga_switcheroo_process_delayed_switch(void) { return 0; } 181 161 static inline enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev) { return VGA_SWITCHEROO_ON; } 182 162