@@ -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);
@@ -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_ */
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(-)