summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/vga
diff options
context:
space:
mode:
authorJim Qu <Jim.Qu@amd.com>2018-07-17 16:20:50 +0800
committerTakashi Iwai <tiwai@suse.de>2018-07-17 11:12:00 +0200
commit4aaf448fa9754e2d5ee188d32327b24ffc15ca4d (patch)
tree1f625d14bdfaf5a48c461c6ce357181dc5d809a4 /drivers/gpu/vga
parent9d3cce1e8b8561fed5f383d22a4d6949db4eadbe (diff)
downloadlinux-4aaf448fa9754e2d5ee188d32327b24ffc15ca4d.tar.bz2
vga_switcheroo: set audio client id according to bound GPU id
On modern laptop, there are more and more platforms have two GPUs, and each of them maybe have audio codec for HDMP/DP output. For some dGPU which is no output, audio codec usually is disabled. In currect HDA audio driver, it will set all codec as VGA_SWITCHEROO_DIS, the audio which is binded to UMA will be suspended if user use debugfs to contorl power In HDA driver side, it is difficult to know which GPU the audio has binded to. So set the bound gpu pci dev to vga_switcheroo. if the audio client is not the third registration, audio id will set in vga_switcheroo enable function. if the audio client is the last registration when vga_switcheroo _ready() get true, we should get audio client id from bound GPU directly. Signed-off-by: Jim Qu <Jim.Qu@amd.com> Reviewed-by: Lukas Wunner <lukas@wunner.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'drivers/gpu/vga')
-rw-r--r--drivers/gpu/vga/vga_switcheroo.c63
1 files changed, 52 insertions, 11 deletions
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index fc4adf3d34e8..a96bf46bc483 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -103,9 +103,11 @@
* runtime pm. If true, writing ON and OFF to the vga_switcheroo debugfs
* interface is a no-op so as not to interfere with runtime pm
* @list: client list
+ * @vga_dev: pci device, indicate which GPU is bound to current audio client
*
* Registered client. A client can be either a GPU or an audio device on a GPU.
- * For audio clients, the @fb_info and @active members are bogus.
+ * For audio clients, the @fb_info and @active members are bogus. For GPU
+ * clients, the @vga_dev is bogus.
*/
struct vga_switcheroo_client {
struct pci_dev *pdev;
@@ -116,6 +118,7 @@ struct vga_switcheroo_client {
bool active;
bool driver_power_control;
struct list_head list;
+ struct pci_dev *vga_dev;
};
/*
@@ -161,9 +164,8 @@ struct vgasr_priv {
};
#define ID_BIT_AUDIO 0x100
-#define client_is_audio(c) ((c)->id & ID_BIT_AUDIO)
-#define client_is_vga(c) ((c)->id == VGA_SWITCHEROO_UNKNOWN_ID || \
- !client_is_audio(c))
+#define client_is_audio(c) ((c)->id & ID_BIT_AUDIO)
+#define client_is_vga(c) (!client_is_audio(c))
#define client_id(c) ((c)->id & ~ID_BIT_AUDIO)
static int vga_switcheroo_debugfs_init(struct vgasr_priv *priv);
@@ -192,14 +194,29 @@ static void vga_switcheroo_enable(void)
vgasr_priv.handler->init();
list_for_each_entry(client, &vgasr_priv.clients, list) {
- if (client->id != VGA_SWITCHEROO_UNKNOWN_ID)
+ if (!client_is_vga(client) ||
+ client_id(client) != VGA_SWITCHEROO_UNKNOWN_ID)
continue;
+
ret = vgasr_priv.handler->get_client_id(client->pdev);
if (ret < 0)
return;
client->id = ret;
}
+
+ list_for_each_entry(client, &vgasr_priv.clients, list) {
+ if (!client_is_audio(client) ||
+ client_id(client) != VGA_SWITCHEROO_UNKNOWN_ID)
+ continue;
+
+ ret = vgasr_priv.handler->get_client_id(client->vga_dev);
+ if (ret < 0)
+ return;
+
+ client->id = ret | ID_BIT_AUDIO;
+ }
+
vga_switcheroo_debugfs_init(&vgasr_priv);
vgasr_priv.active = true;
}
@@ -272,7 +289,9 @@ EXPORT_SYMBOL(vga_switcheroo_handler_flags);
static int register_client(struct pci_dev *pdev,
const struct vga_switcheroo_client_ops *ops,
- enum vga_switcheroo_client_id id, bool active,
+ enum vga_switcheroo_client_id id,
+ struct pci_dev *vga_dev,
+ bool active,
bool driver_power_control)
{
struct vga_switcheroo_client *client;
@@ -287,6 +306,7 @@ static int register_client(struct pci_dev *pdev,
client->id = id;
client->active = active;
client->driver_power_control = driver_power_control;
+ client->vga_dev = vga_dev;
mutex_lock(&vgasr_mutex);
list_add_tail(&client->list, &vgasr_priv.clients);
@@ -319,7 +339,7 @@ int vga_switcheroo_register_client(struct pci_dev *pdev,
const struct vga_switcheroo_client_ops *ops,
bool driver_power_control)
{
- return register_client(pdev, ops, VGA_SWITCHEROO_UNKNOWN_ID,
+ return register_client(pdev, ops, VGA_SWITCHEROO_UNKNOWN_ID, NULL,
pdev == vga_default_device(),
driver_power_control);
}
@@ -329,19 +349,40 @@ EXPORT_SYMBOL(vga_switcheroo_register_client);
* vga_switcheroo_register_audio_client - register audio client
* @pdev: client pci device
* @ops: client callbacks
- * @id: client identifier
+ * @vga_dev: pci device which is bound to current audio client
*
* Register audio client (audio device on a GPU). The client is assumed
* to use runtime PM. Beforehand, vga_switcheroo_client_probe_defer()
* shall be called to ensure that all prerequisites are met.
*
- * Return: 0 on success, -ENOMEM on memory allocation error.
+ * Return: 0 on success, -ENOMEM on memory allocation error, -EINVAL on getting
+ * client id error.
*/
int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
const struct vga_switcheroo_client_ops *ops,
- enum vga_switcheroo_client_id id)
+ struct pci_dev *vga_dev)
{
- return register_client(pdev, ops, id | ID_BIT_AUDIO, false, true);
+ enum vga_switcheroo_client_id id = VGA_SWITCHEROO_UNKNOWN_ID;
+
+ /*
+ * if vga_switcheroo has enabled, that mean two GPU clients and also
+ * handler are registered. Get audio client id from bound GPU client
+ * id directly, otherwise, set it as VGA_SWITCHEROO_UNKNOWN_ID,
+ * it will set to correct id in later when vga_switcheroo_enable()
+ * is called.
+ */
+ mutex_lock(&vgasr_mutex);
+ if (vgasr_priv.active) {
+ id = vgasr_priv.handler->get_client_id(vga_dev);
+ if (id < 0) {
+ mutex_unlock(&vgasr_mutex);
+ return -EINVAL;
+ }
+ }
+ mutex_unlock(&vgasr_mutex);
+
+ return register_client(pdev, ops, id | ID_BIT_AUDIO, vga_dev,
+ false, true);
}
EXPORT_SYMBOL(vga_switcheroo_register_audio_client);