^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * vga_switcheroo.c - Support for laptop with dual GPU using one set of outputs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (c) 2010 Red Hat Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Author : Dave Airlie <airlied@redhat.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (c) 2015 Lukas Wunner <lukas@wunner.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Permission is hereby granted, free of charge, to any person obtaining a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * copy of this software and associated documentation files (the "Software"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * to deal in the Software without restriction, including without limitation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * the rights to use, copy, modify, merge, publish, distribute, sublicense,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * and/or sell copies of the Software, and to permit persons to whom the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Software is furnished to do so, subject to the following conditions:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * The above copyright notice and this permission notice (including the next
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * paragraph) shall be included in all copies or substantial portions of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * Software.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * DEALINGS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * IN THE SOFTWARE.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define pr_fmt(fmt) "vga_switcheroo: " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/apple-gmux.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/debugfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <linux/fbcon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <linux/pm_domain.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include <linux/pm_runtime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #include <linux/vgaarb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #include <linux/vga_switcheroo.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * DOC: Overview
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * vga_switcheroo is the Linux subsystem for laptop hybrid graphics.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * These come in two flavors:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * * muxed: Dual GPUs with a multiplexer chip to switch outputs between GPUs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * * muxless: Dual GPUs but only one of them is connected to outputs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * The other one is merely used to offload rendering, its results
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * are copied over PCIe into the framebuffer. On Linux this is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * supported with DRI PRIME.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * Hybrid graphics started to appear in the late Naughties and were initially
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * all muxed. Newer laptops moved to a muxless architecture for cost reasons.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * A notable exception is the MacBook Pro which continues to use a mux.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * Muxes come with varying capabilities: Some switch only the panel, others
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * can also switch external displays. Some switch all display pins at once
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * while others can switch just the DDC lines. (To allow EDID probing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * for the inactive GPU.) Also, muxes are often used to cut power to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * discrete GPU while it is not used.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * DRM drivers register GPUs with vga_switcheroo, these are henceforth called
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * clients. The mux is called the handler. Muxless machines also register a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * handler to control the power state of the discrete GPU, its ->switchto
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * callback is a no-op for obvious reasons. The discrete GPU is often equipped
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * with an HDA controller for the HDMI/DP audio signal, this will also
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * register as a client so that vga_switcheroo can take care of the correct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * suspend/resume order when changing the discrete GPU's power state. In total
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * there can thus be up to three clients: Two vga clients (GPUs) and one audio
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * client (on the discrete GPU). The code is mostly prepared to support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * machines with more than two GPUs should they become available.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * The GPU to which the outputs are currently switched is called the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * active client in vga_switcheroo parlance. The GPU not in use is the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * inactive client. When the inactive client's DRM driver is loaded,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * it will be unable to probe the panel's EDID and hence depends on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * VBIOS to provide its display modes. If the VBIOS modes are bogus or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * if there is no VBIOS at all (which is common on the MacBook Pro),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * a client may alternatively request that the DDC lines are temporarily
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * switched to it, provided that the handler supports this. Switching
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * only the DDC lines and not the entire output avoids unnecessary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * flickering.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * struct vga_switcheroo_client - registered client
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * @pdev: client pci device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * @fb_info: framebuffer to which console is remapped on switching
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * @pwr_state: current power state if manual power control is used.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * For driver power control, call vga_switcheroo_pwr_state().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * @ops: client callbacks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * @id: client identifier. Determining the id requires the handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * so gpus are initially assigned VGA_SWITCHEROO_UNKNOWN_ID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * and later given their true id in vga_switcheroo_enable()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * @active: whether the outputs are currently switched to this client
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * @driver_power_control: whether power state is controlled by the driver's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * runtime pm. If true, writing ON and OFF to the vga_switcheroo debugfs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * interface is a no-op so as not to interfere with runtime pm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * @list: client list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * @vga_dev: pci device, indicate which GPU is bound to current audio client
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * Registered client. A client can be either a GPU or an audio device on a GPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * For audio clients, the @fb_info and @active members are bogus. For GPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * clients, the @vga_dev is bogus.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) struct vga_switcheroo_client {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct pci_dev *pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct fb_info *fb_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) enum vga_switcheroo_state pwr_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) const struct vga_switcheroo_client_ops *ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) enum vga_switcheroo_client_id id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) bool active;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) bool driver_power_control;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) struct pci_dev *vga_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * protects access to struct vgasr_priv
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static DEFINE_MUTEX(vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * struct vgasr_priv - vga_switcheroo private data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * @active: whether vga_switcheroo is enabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * Prerequisite is the registration of two GPUs and a handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * @delayed_switch_active: whether a delayed switch is pending
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * @delayed_client_id: client to which a delayed switch is pending
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * @debugfs_root: directory for vga_switcheroo debugfs interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * @registered_clients: number of registered GPUs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * (counting only vga clients, not audio clients)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * @clients: list of registered clients
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * @handler: registered handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * @handler_flags: flags of registered handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * @mux_hw_lock: protects mux state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * (in particular while DDC lines are temporarily switched)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * @old_ddc_owner: client to which DDC lines will be switched back on unlock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * vga_switcheroo private data. Currently only one vga_switcheroo instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * per system is supported.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) struct vgasr_priv {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) bool active;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) bool delayed_switch_active;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) enum vga_switcheroo_client_id delayed_client_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) struct dentry *debugfs_root;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) int registered_clients;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) struct list_head clients;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) const struct vga_switcheroo_handler *handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) enum vga_switcheroo_handler_flags_t handler_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) struct mutex mux_hw_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) int old_ddc_owner;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) #define ID_BIT_AUDIO 0x100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) #define client_is_audio(c) ((c)->id & ID_BIT_AUDIO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) #define client_is_vga(c) (!client_is_audio(c))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) #define client_id(c) ((c)->id & ~ID_BIT_AUDIO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) static void vga_switcheroo_debugfs_init(struct vgasr_priv *priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) /* only one switcheroo per system */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static struct vgasr_priv vgasr_priv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .clients = LIST_HEAD_INIT(vgasr_priv.clients),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) .mux_hw_lock = __MUTEX_INITIALIZER(vgasr_priv.mux_hw_lock),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) static bool vga_switcheroo_ready(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) /* we're ready if we get two clients + handler */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return !vgasr_priv.active &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) vgasr_priv.registered_clients == 2 && vgasr_priv.handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) static void vga_switcheroo_enable(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) struct vga_switcheroo_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) /* call the handler to init */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (vgasr_priv.handler->init)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) vgasr_priv.handler->init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) list_for_each_entry(client, &vgasr_priv.clients, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) if (!client_is_vga(client) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) client_id(client) != VGA_SWITCHEROO_UNKNOWN_ID)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) ret = vgasr_priv.handler->get_client_id(client->pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) client->id = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) list_for_each_entry(client, &vgasr_priv.clients, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) if (!client_is_audio(client) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) client_id(client) != VGA_SWITCHEROO_UNKNOWN_ID)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) ret = vgasr_priv.handler->get_client_id(client->vga_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) client->id = ret | ID_BIT_AUDIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (client->ops->gpu_bound)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) client->ops->gpu_bound(client->pdev, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) vga_switcheroo_debugfs_init(&vgasr_priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) vgasr_priv.active = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) * vga_switcheroo_register_handler() - register handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) * @handler: handler callbacks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) * @handler_flags: handler flags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) * Register handler. Enable vga_switcheroo if two vga clients have already
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) * registered.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) * Return: 0 on success, -EINVAL if a handler was already registered.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) int vga_switcheroo_register_handler(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) const struct vga_switcheroo_handler *handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) enum vga_switcheroo_handler_flags_t handler_flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) mutex_lock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) if (vgasr_priv.handler) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) mutex_unlock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) vgasr_priv.handler = handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) vgasr_priv.handler_flags = handler_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if (vga_switcheroo_ready()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) pr_info("enabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) vga_switcheroo_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) mutex_unlock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) EXPORT_SYMBOL(vga_switcheroo_register_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) * vga_switcheroo_unregister_handler() - unregister handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) * Unregister handler. Disable vga_switcheroo.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) void vga_switcheroo_unregister_handler(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) mutex_lock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) mutex_lock(&vgasr_priv.mux_hw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) vgasr_priv.handler_flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) vgasr_priv.handler = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) if (vgasr_priv.active) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) pr_info("disabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) vga_switcheroo_debugfs_fini(&vgasr_priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) vgasr_priv.active = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) mutex_unlock(&vgasr_priv.mux_hw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) mutex_unlock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) * vga_switcheroo_handler_flags() - obtain handler flags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) * Helper for clients to obtain the handler flags bitmask.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) * Return: Handler flags. A value of 0 means that no handler is registered
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) * or that the handler has no special capabilities.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) enum vga_switcheroo_handler_flags_t vga_switcheroo_handler_flags(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) return vgasr_priv.handler_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) EXPORT_SYMBOL(vga_switcheroo_handler_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) static int register_client(struct pci_dev *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) const struct vga_switcheroo_client_ops *ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) enum vga_switcheroo_client_id id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) struct pci_dev *vga_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) bool active,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) bool driver_power_control)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) struct vga_switcheroo_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) client = kzalloc(sizeof(*client), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) if (!client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) client->pwr_state = VGA_SWITCHEROO_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) client->pdev = pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) client->ops = ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) client->id = id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) client->active = active;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) client->driver_power_control = driver_power_control;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) client->vga_dev = vga_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) mutex_lock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) list_add_tail(&client->list, &vgasr_priv.clients);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) if (client_is_vga(client))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) vgasr_priv.registered_clients++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (vga_switcheroo_ready()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) pr_info("enabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) vga_switcheroo_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) mutex_unlock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) * vga_switcheroo_register_client - register vga client
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) * @pdev: client pci device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) * @ops: client callbacks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) * @driver_power_control: whether power state is controlled by the driver's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) * runtime pm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) * Register vga client (GPU). Enable vga_switcheroo if another GPU and a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) * handler have already registered. The power state of the client is assumed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) * to be ON. Beforehand, vga_switcheroo_client_probe_defer() shall be called
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) * to ensure that all prerequisites are met.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) * Return: 0 on success, -ENOMEM on memory allocation error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) int vga_switcheroo_register_client(struct pci_dev *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) const struct vga_switcheroo_client_ops *ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) bool driver_power_control)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) return register_client(pdev, ops, VGA_SWITCHEROO_UNKNOWN_ID, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) pdev == vga_default_device(),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) driver_power_control);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) EXPORT_SYMBOL(vga_switcheroo_register_client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) * vga_switcheroo_register_audio_client - register audio client
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) * @pdev: client pci device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) * @ops: client callbacks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) * @vga_dev: pci device which is bound to current audio client
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) * Register audio client (audio device on a GPU). The client is assumed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) * to use runtime PM. Beforehand, vga_switcheroo_client_probe_defer()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) * shall be called to ensure that all prerequisites are met.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) * Return: 0 on success, -ENOMEM on memory allocation error, -EINVAL on getting
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) * client id error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) const struct vga_switcheroo_client_ops *ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) struct pci_dev *vga_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) enum vga_switcheroo_client_id id = VGA_SWITCHEROO_UNKNOWN_ID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) * if vga_switcheroo has enabled, that mean two GPU clients and also
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) * handler are registered. Get audio client id from bound GPU client
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) * id directly, otherwise, set it as VGA_SWITCHEROO_UNKNOWN_ID,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) * it will set to correct id in later when vga_switcheroo_enable()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) * is called.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) mutex_lock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) if (vgasr_priv.active) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) id = vgasr_priv.handler->get_client_id(vga_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) if (id < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) mutex_unlock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) /* notify if GPU has been already bound */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if (ops->gpu_bound)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) ops->gpu_bound(pdev, id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) mutex_unlock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) return register_client(pdev, ops, id | ID_BIT_AUDIO, vga_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) false, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) EXPORT_SYMBOL(vga_switcheroo_register_audio_client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) static struct vga_switcheroo_client *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) find_client_from_pci(struct list_head *head, struct pci_dev *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) struct vga_switcheroo_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) list_for_each_entry(client, head, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) if (client->pdev == pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) return client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) static struct vga_switcheroo_client *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) find_client_from_id(struct list_head *head,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) enum vga_switcheroo_client_id client_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) struct vga_switcheroo_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) list_for_each_entry(client, head, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) if (client->id == client_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) return client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) static struct vga_switcheroo_client *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) find_active_client(struct list_head *head)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) struct vga_switcheroo_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) list_for_each_entry(client, head, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) if (client->active)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) return client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) * vga_switcheroo_client_probe_defer() - whether to defer probing a given client
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) * @pdev: client pci device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) * Determine whether any prerequisites are not fulfilled to probe a given
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) * client. Drivers shall invoke this early on in their ->probe callback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) * and return %-EPROBE_DEFER if it evaluates to %true. Thou shalt not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) * register the client ere thou hast called this.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) * Return: %true if probing should be deferred, otherwise %false.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) * apple-gmux is needed on pre-retina MacBook Pro
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) * to probe the panel if pdev is the inactive GPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) if (apple_gmux_present() && pdev != vga_default_device() &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) !vgasr_priv.handler_flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) EXPORT_SYMBOL(vga_switcheroo_client_probe_defer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) static enum vga_switcheroo_state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) vga_switcheroo_pwr_state(struct vga_switcheroo_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if (client->driver_power_control)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) if (pm_runtime_enabled(&client->pdev->dev) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) pm_runtime_active(&client->pdev->dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) return VGA_SWITCHEROO_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) return VGA_SWITCHEROO_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) return client->pwr_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) * vga_switcheroo_get_client_state() - obtain power state of a given client
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) * @pdev: client pci device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) * Obtain power state of a given client as seen from vga_switcheroo.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) * The function is only called from hda_intel.c.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) * Return: Power state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) struct vga_switcheroo_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) enum vga_switcheroo_state ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) mutex_lock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) client = find_client_from_pci(&vgasr_priv.clients, pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) if (!client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) ret = VGA_SWITCHEROO_NOT_FOUND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) ret = vga_switcheroo_pwr_state(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) mutex_unlock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) EXPORT_SYMBOL(vga_switcheroo_get_client_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) * vga_switcheroo_unregister_client() - unregister client
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) * @pdev: client pci device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) * Unregister client. Disable vga_switcheroo if this is a vga client (GPU).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) void vga_switcheroo_unregister_client(struct pci_dev *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) struct vga_switcheroo_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) mutex_lock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) client = find_client_from_pci(&vgasr_priv.clients, pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) if (client) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if (client_is_vga(client))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) vgasr_priv.registered_clients--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) list_del(&client->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) kfree(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) if (vgasr_priv.active && vgasr_priv.registered_clients < 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) pr_info("disabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) vga_switcheroo_debugfs_fini(&vgasr_priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) vgasr_priv.active = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) mutex_unlock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) EXPORT_SYMBOL(vga_switcheroo_unregister_client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) * vga_switcheroo_client_fb_set() - set framebuffer of a given client
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) * @pdev: client pci device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) * @info: framebuffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) * Set framebuffer of a given client. The console will be remapped to this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) * on switching.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) struct vga_switcheroo_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) mutex_lock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) client = find_client_from_pci(&vgasr_priv.clients, pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) if (client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) client->fb_info = info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) mutex_unlock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) EXPORT_SYMBOL(vga_switcheroo_client_fb_set);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) * vga_switcheroo_lock_ddc() - temporarily switch DDC lines to a given client
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) * @pdev: client pci device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) * Temporarily switch DDC lines to the client identified by @pdev
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) * (but leave the outputs otherwise switched to where they are).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) * This allows the inactive client to probe EDID. The DDC lines must
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) * afterwards be switched back by calling vga_switcheroo_unlock_ddc(),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) * even if this function returns an error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) * Return: Previous DDC owner on success or a negative int on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) * Specifically, %-ENODEV if no handler has registered or if the handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) * does not support switching the DDC lines. Also, a negative value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) * returned by the handler is propagated back to the caller.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) * The return value has merely an informational purpose for any caller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) * which might be interested in it. It is acceptable to ignore the return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) * value and simply rely on the result of the subsequent EDID probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) * which will be %NULL if DDC switching failed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) int vga_switcheroo_lock_ddc(struct pci_dev *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) enum vga_switcheroo_client_id id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) mutex_lock(&vgasr_priv.mux_hw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) if (!vgasr_priv.handler || !vgasr_priv.handler->switch_ddc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) vgasr_priv.old_ddc_owner = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) id = vgasr_priv.handler->get_client_id(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) vgasr_priv.old_ddc_owner = vgasr_priv.handler->switch_ddc(id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) return vgasr_priv.old_ddc_owner;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) EXPORT_SYMBOL(vga_switcheroo_lock_ddc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) * vga_switcheroo_unlock_ddc() - switch DDC lines back to previous owner
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) * @pdev: client pci device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) * Switch DDC lines back to the previous owner after calling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) * vga_switcheroo_lock_ddc(). This must be called even if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) * vga_switcheroo_lock_ddc() returned an error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) * Return: Previous DDC owner on success (i.e. the client identifier of @pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) * or a negative int on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) * Specifically, %-ENODEV if no handler has registered or if the handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) * does not support switching the DDC lines. Also, a negative value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) * returned by the handler is propagated back to the caller.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) * Finally, invoking this function without calling vga_switcheroo_lock_ddc()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) * first is not allowed and will result in %-EINVAL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) int vga_switcheroo_unlock_ddc(struct pci_dev *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) enum vga_switcheroo_client_id id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) int ret = vgasr_priv.old_ddc_owner;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) if (WARN_ON_ONCE(!mutex_is_locked(&vgasr_priv.mux_hw_lock)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) if (vgasr_priv.old_ddc_owner >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) id = vgasr_priv.handler->get_client_id(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) if (vgasr_priv.old_ddc_owner != id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) ret = vgasr_priv.handler->switch_ddc(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) vgasr_priv.old_ddc_owner);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) mutex_unlock(&vgasr_priv.mux_hw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) EXPORT_SYMBOL(vga_switcheroo_unlock_ddc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) * DOC: Manual switching and manual power control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) * In this mode of use, the file /sys/kernel/debug/vgaswitcheroo/switch
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) * can be read to retrieve the current vga_switcheroo state and commands
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) * can be written to it to change the state. The file appears as soon as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) * two GPU drivers and one handler have registered with vga_switcheroo.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) * The following commands are understood:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) * * OFF: Power off the device not in use.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) * * ON: Power on the device not in use.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) * * IGD: Switch to the integrated graphics device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) * Power on the integrated GPU if necessary, power off the discrete GPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) * Prerequisite is that no user space processes (e.g. Xorg, alsactl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) * have opened device files of the GPUs or the audio client. If the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) * switch fails, the user may invoke lsof(8) or fuser(1) on /dev/dri/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) * and /dev/snd/controlC1 to identify processes blocking the switch.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) * * DIS: Switch to the discrete graphics device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) * * DIGD: Delayed switch to the integrated graphics device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) * This will perform the switch once the last user space process has
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) * closed the device files of the GPUs and the audio client.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) * * DDIS: Delayed switch to the discrete graphics device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) * * MIGD: Mux-only switch to the integrated graphics device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) * Does not remap console or change the power state of either gpu.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) * If the integrated GPU is currently off, the screen will turn black.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) * If it is on, the screen will show whatever happens to be in VRAM.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) * Either way, the user has to blindly enter the command to switch back.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) * * MDIS: Mux-only switch to the discrete graphics device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) * For GPUs whose power state is controlled by the driver's runtime pm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) * the ON and OFF commands are a no-op (see next section).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) * For muxless machines, the IGD/DIS, DIGD/DDIS and MIGD/MDIS commands
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) * should not be used.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) static int vga_switcheroo_show(struct seq_file *m, void *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) struct vga_switcheroo_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) mutex_lock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) list_for_each_entry(client, &vgasr_priv.clients, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) seq_printf(m, "%d:%s%s:%c:%s%s:%s\n", i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) client_id(client) == VGA_SWITCHEROO_DIS ? "DIS" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) "IGD",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) client_is_vga(client) ? "" : "-Audio",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) client->active ? '+' : ' ',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) client->driver_power_control ? "Dyn" : "",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) vga_switcheroo_pwr_state(client) ? "Pwr" : "Off",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) pci_name(client->pdev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) mutex_unlock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) static int vga_switcheroo_debugfs_open(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) return single_open(file, vga_switcheroo_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) static int vga_switchon(struct vga_switcheroo_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) if (client->driver_power_control)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) if (vgasr_priv.handler->power_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) /* call the driver callback to turn on device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) client->ops->set_gpu_state(client->pdev, VGA_SWITCHEROO_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) client->pwr_state = VGA_SWITCHEROO_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) static int vga_switchoff(struct vga_switcheroo_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) if (client->driver_power_control)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) /* call the driver callback to turn off device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) client->ops->set_gpu_state(client->pdev, VGA_SWITCHEROO_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) if (vgasr_priv.handler->power_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) client->pwr_state = VGA_SWITCHEROO_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) static void set_audio_state(enum vga_switcheroo_client_id id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) enum vga_switcheroo_state state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) struct vga_switcheroo_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) client = find_client_from_id(&vgasr_priv.clients, id | ID_BIT_AUDIO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) if (client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) client->ops->set_gpu_state(client->pdev, state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) /* stage one happens before delay */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) struct vga_switcheroo_client *active;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) active = find_active_client(&vgasr_priv.clients);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) if (!active)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) if (vga_switcheroo_pwr_state(new_client) == VGA_SWITCHEROO_OFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) vga_switchon(new_client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) vga_set_default_device(new_client->pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) /* post delay */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) struct vga_switcheroo_client *active;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) active = find_active_client(&vgasr_priv.clients);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) if (!active)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) active->active = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) /* let HDA controller autosuspend if GPU uses driver power control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) if (!active->driver_power_control)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) set_audio_state(active->id, VGA_SWITCHEROO_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) if (new_client->fb_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) fbcon_remap_all(new_client->fb_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) mutex_lock(&vgasr_priv.mux_hw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) ret = vgasr_priv.handler->switchto(new_client->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) mutex_unlock(&vgasr_priv.mux_hw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) if (new_client->ops->reprobe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) new_client->ops->reprobe(new_client->pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) if (vga_switcheroo_pwr_state(active) == VGA_SWITCHEROO_ON)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) vga_switchoff(active);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) /* let HDA controller autoresume if GPU uses driver power control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) if (!new_client->driver_power_control)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) set_audio_state(new_client->id, VGA_SWITCHEROO_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) new_client->active = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) static bool check_can_switch(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) struct vga_switcheroo_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) list_for_each_entry(client, &vgasr_priv.clients, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) if (!client->ops->can_switch(client->pdev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) pr_err("client %x refused switch\n", client->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) size_t cnt, loff_t *ppos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) char usercmd[64];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) bool delay = false, can_switch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) bool just_mux = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) enum vga_switcheroo_client_id client_id = VGA_SWITCHEROO_UNKNOWN_ID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) struct vga_switcheroo_client *client = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) if (cnt > 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) cnt = 63;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) if (copy_from_user(usercmd, ubuf, cnt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) mutex_lock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) if (!vgasr_priv.active) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) cnt = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) /* pwr off the device not in use */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) if (strncmp(usercmd, "OFF", 3) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) list_for_each_entry(client, &vgasr_priv.clients, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) if (client->active || client_is_audio(client))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) if (client->driver_power_control)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) set_audio_state(client->id, VGA_SWITCHEROO_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) if (client->pwr_state == VGA_SWITCHEROO_ON)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) vga_switchoff(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) /* pwr on the device not in use */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) if (strncmp(usercmd, "ON", 2) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) list_for_each_entry(client, &vgasr_priv.clients, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) if (client->active || client_is_audio(client))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) if (client->driver_power_control)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) if (client->pwr_state == VGA_SWITCHEROO_OFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) vga_switchon(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) set_audio_state(client->id, VGA_SWITCHEROO_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) /* request a delayed switch - test can we switch now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) if (strncmp(usercmd, "DIGD", 4) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) client_id = VGA_SWITCHEROO_IGD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) delay = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) if (strncmp(usercmd, "DDIS", 4) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) client_id = VGA_SWITCHEROO_DIS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) delay = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) if (strncmp(usercmd, "IGD", 3) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) client_id = VGA_SWITCHEROO_IGD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) if (strncmp(usercmd, "DIS", 3) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) client_id = VGA_SWITCHEROO_DIS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) if (strncmp(usercmd, "MIGD", 4) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) just_mux = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) client_id = VGA_SWITCHEROO_IGD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) if (strncmp(usercmd, "MDIS", 4) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) just_mux = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) client_id = VGA_SWITCHEROO_DIS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) if (client_id == VGA_SWITCHEROO_UNKNOWN_ID)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) client = find_client_from_id(&vgasr_priv.clients, client_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) if (!client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) vgasr_priv.delayed_switch_active = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) if (just_mux) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) mutex_lock(&vgasr_priv.mux_hw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) ret = vgasr_priv.handler->switchto(client_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) mutex_unlock(&vgasr_priv.mux_hw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) if (client->active)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) /* okay we want a switch - test if devices are willing to switch */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) can_switch = check_can_switch();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) if (can_switch == false && delay == false)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) if (can_switch) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) ret = vga_switchto_stage1(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) pr_err("switching failed stage 1 %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) ret = vga_switchto_stage2(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) pr_err("switching failed stage 2 %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) pr_info("setting delayed switch to client %d\n", client->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) vgasr_priv.delayed_switch_active = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) vgasr_priv.delayed_client_id = client_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) ret = vga_switchto_stage1(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) pr_err("delayed switching stage 1 failed %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) mutex_unlock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) return cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) static const struct file_operations vga_switcheroo_debugfs_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) .open = vga_switcheroo_debugfs_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) .write = vga_switcheroo_debugfs_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) .read = seq_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) .llseek = seq_lseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) .release = single_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) debugfs_remove_recursive(priv->debugfs_root);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) priv->debugfs_root = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) static void vga_switcheroo_debugfs_init(struct vgasr_priv *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) /* already initialised */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) if (priv->debugfs_root)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) priv->debugfs_root = debugfs_create_dir("vgaswitcheroo", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) debugfs_create_file("switch", 0644, priv->debugfs_root, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) &vga_switcheroo_debugfs_fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) * vga_switcheroo_process_delayed_switch() - helper for delayed switching
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) * Process a delayed switch if one is pending. DRM drivers should call this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) * from their ->lastclose callback.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) * Return: 0 on success. -EINVAL if no delayed switch is pending, if the client
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) * has unregistered in the meantime or if there are other clients blocking the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) * switch. If the actual switch fails, an error is reported and 0 is returned.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) int vga_switcheroo_process_delayed_switch(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) struct vga_switcheroo_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) int err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) mutex_lock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) if (!vgasr_priv.delayed_switch_active)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) pr_info("processing delayed switch to %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) vgasr_priv.delayed_client_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) client = find_client_from_id(&vgasr_priv.clients,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) vgasr_priv.delayed_client_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) if (!client || !check_can_switch())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) ret = vga_switchto_stage2(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) pr_err("delayed switching failed stage 2 %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) vgasr_priv.delayed_switch_active = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) mutex_unlock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) * DOC: Driver power control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) * In this mode of use, the discrete GPU automatically powers up and down at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) * the discretion of the driver's runtime pm. On muxed machines, the user may
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) * still influence the muxer state by way of the debugfs interface, however
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) * the ON and OFF commands become a no-op for the discrete GPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) * This mode is the default on Nvidia HybridPower/Optimus and ATI PowerXpress.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) * Specifying nouveau.runpm=0, radeon.runpm=0 or amdgpu.runpm=0 on the kernel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) * command line disables it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) * After the GPU has been suspended, the handler needs to be called to cut
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) * power to the GPU. Likewise it needs to reinstate power before the GPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) * can resume. This is achieved by vga_switcheroo_init_domain_pm_ops(),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) * which augments the GPU's suspend/resume functions by the requisite
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) * calls to the handler.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) * When the audio device resumes, the GPU needs to be woken. This is achieved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) * by a PCI quirk which calls device_link_add() to declare a dependency on the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) * GPU. That way, the GPU is kept awake whenever and as long as the audio
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) * device is in use.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) * On muxed machines, if the mux is initially switched to the discrete GPU,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) * the user ends up with a black screen when the GPU powers down after boot.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) * As a workaround, the mux is forced to the integrated GPU on runtime suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) * cf. https://bugs.freedesktop.org/show_bug.cgi?id=75917
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) static void vga_switcheroo_power_switch(struct pci_dev *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) enum vga_switcheroo_state state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) struct vga_switcheroo_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) if (!vgasr_priv.handler->power_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) client = find_client_from_pci(&vgasr_priv.clients, pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) if (!client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) if (!client->driver_power_control)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) vgasr_priv.handler->power_state(client->id, state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) /* switcheroo power domain */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) static int vga_switcheroo_runtime_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) struct pci_dev *pdev = to_pci_dev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) ret = dev->bus->pm->runtime_suspend(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) mutex_lock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) if (vgasr_priv.handler->switchto) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) mutex_lock(&vgasr_priv.mux_hw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) vgasr_priv.handler->switchto(VGA_SWITCHEROO_IGD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) mutex_unlock(&vgasr_priv.mux_hw_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) pci_bus_set_current_state(pdev->bus, PCI_D3cold);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) mutex_unlock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) static int vga_switcheroo_runtime_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) struct pci_dev *pdev = to_pci_dev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) mutex_lock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) mutex_unlock(&vgasr_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) pci_wakeup_bus(pdev->bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) ret = dev->bus->pm->runtime_resume(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) * vga_switcheroo_init_domain_pm_ops() - helper for driver power control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) * @dev: vga client device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) * @domain: power domain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) * Helper for GPUs whose power state is controlled by the driver's runtime pm.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) * After the GPU has been suspended, the handler needs to be called to cut
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) * power to the GPU. Likewise it needs to reinstate power before the GPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) * can resume. To this end, this helper augments the suspend/resume functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) * by the requisite calls to the handler. It needs only be called on platforms
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) * where the power switch is separate to the device being powered down.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) int vga_switcheroo_init_domain_pm_ops(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) struct dev_pm_domain *domain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) /* copy over all the bus versions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) if (dev->bus && dev->bus->pm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) domain->ops = *dev->bus->pm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) domain->ops.runtime_suspend = vga_switcheroo_runtime_suspend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) domain->ops.runtime_resume = vga_switcheroo_runtime_resume;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) dev_pm_domain_set(dev, domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) dev_pm_domain_set(dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) EXPORT_SYMBOL(vga_switcheroo_init_domain_pm_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) void vga_switcheroo_fini_domain_pm_ops(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) dev_pm_domain_set(dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) EXPORT_SYMBOL(vga_switcheroo_fini_domain_pm_ops);