diff mbox series

[2/6] vga-switcheroo: Add a way to test for the active client

Message ID 20200727205112.27698-3-ddadap@nvidia.com (mailing list archive)
State New, archived
Headers show
Series vga-switcheroo: initial dynamic mux switch support | expand

Commit Message

Daniel Dadap July 27, 2020, 8:51 p.m. UTC
vga-switcheroo clients may wish to know whether they are currently
active, i.e., whether the mux is currently switched to the client
in question. Add an in-kernel API to test whether a vga-switcheroo
client, as identified by PCI device, is actively switched.

Signed-off-by: Daniel Dadap <ddadap@nvidia.com>
---
 drivers/gpu/vga/vga_switcheroo.c | 38 +++++++++++++++++++++++++++++++-
 include/linux/vga_switcheroo.h   |  2 ++
 2 files changed, 39 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index cf3c7024dafa..a4fc78c4bf4f 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -99,7 +99,13 @@ 
  * @id: client identifier. Determining the id requires the handler,
  *	so gpus are initially assigned VGA_SWITCHEROO_UNKNOWN_ID
  *	and later given their true id in vga_switcheroo_enable()
- * @active: whether the outputs are currently switched to this client
+ * @active: whether the client is currently active: this is unset for the
+ *	currently active client before preparing for a mux switch, and set
+ *	for the newly active client after completing all post-switch actions.
+ * @switched: whether the outputs are physically switched to the client:
+ *	this is unset for the currently switched client immediately before
+ *	switching the mux, and set for the newly switched client immediately
+ *	after switching the mux.
  * @driver_power_control: whether power state is controlled by the driver's
  *	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
@@ -117,6 +123,7 @@  struct vga_switcheroo_client {
 	const struct vga_switcheroo_client_ops *ops;
 	enum vga_switcheroo_client_id id;
 	bool active;
+	bool switched;
 	bool driver_power_control;
 	struct list_head list;
 	struct pci_dev *vga_dev;
@@ -306,6 +313,7 @@  static int register_client(struct pci_dev *pdev,
 	client->ops = ops;
 	client->id = id;
 	client->active = active;
+	client->switched = active;
 	client->driver_power_control = driver_power_control;
 	client->vga_dev = vga_dev;
 
@@ -748,11 +756,13 @@  static int vga_switchto_stage2(struct vga_switcheroo_client *new_client,
 	if (new_client->fb_info)
 		fbcon_remap_all(new_client->fb_info);
 
+	active->switched = false;
 	mutex_lock(&vgasr_priv.mux_hw_lock);
 	ret = vgasr_priv.handler->switchto(new_client->id);
 	mutex_unlock(&vgasr_priv.mux_hw_lock);
 	if (ret)
 		return ret;
+	new_client->switched = true;
 
 	if (new_client->ops->reprobe)
 		new_client->ops->reprobe(new_client->pdev);
@@ -1111,3 +1121,29 @@  void vga_switcheroo_fini_domain_pm_ops(struct device *dev)
 	dev_pm_domain_set(dev, NULL);
 }
 EXPORT_SYMBOL(vga_switcheroo_fini_domain_pm_ops);
+
+/**
+ * vga_switcheroo_is_client_active() - test if a device is the active client
+ * @pdev: vga client device
+ *
+ * Check whether the mux is switched to the switcheroo client associated with
+ * the given PCI device. Assumes that mux is always switched to the device in
+ * question when switcheroo is inactive, and that the mux is switched away if
+ * no matching client is registered.
+ */
+bool vga_switcheroo_is_client_active(struct pci_dev *pdev)
+{
+	if (vgasr_priv.active) {
+		struct vga_switcheroo_client *client;
+
+		client = find_client_from_pci(&vgasr_priv.clients, pdev);
+
+		if (client)
+			return client->switched;
+		else
+			return false;
+	} else {
+		return true;
+	}
+}
+EXPORT_SYMBOL(vga_switcheroo_is_client_active);
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index 7e6ac0114d55..63e6d6e5786e 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -173,6 +173,7 @@  enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev);
 
 int vga_switcheroo_init_domain_pm_ops(struct device *dev, struct dev_pm_domain *domain);
 void vga_switcheroo_fini_domain_pm_ops(struct device *dev);
+bool vga_switcheroo_is_client_active(struct pci_dev *pdev);
 #else
 
 static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
@@ -194,6 +195,7 @@  static inline enum vga_switcheroo_state vga_switcheroo_get_client_state(struct p
 
 static inline int vga_switcheroo_init_domain_pm_ops(struct device *dev, struct dev_pm_domain *domain) { return -EINVAL; }
 static inline void vga_switcheroo_fini_domain_pm_ops(struct device *dev) {}
+static inline bool vga_switcheroo_is_client_active(struct pci_dev *pdev) { return true; }
 
 #endif
 #endif /* _LINUX_VGA_SWITCHEROO_H_ */