Home | History | Annotate | Line # | Download | only in i915
      1 /*	$NetBSD: i915_switcheroo.c,v 1.2 2021/12/18 23:45:28 riastradh Exp $	*/
      2 
      3 // SPDX-License-Identifier: MIT
      4 /*
      5  * Copyright  2019 Intel Corporation
      6  */
      7 
      8 #include <sys/cdefs.h>
      9 __KERNEL_RCSID(0, "$NetBSD: i915_switcheroo.c,v 1.2 2021/12/18 23:45:28 riastradh Exp $");
     10 
     11 #include <linux/vga_switcheroo.h>
     12 
     13 #include "i915_drv.h"
     14 #include "i915_switcheroo.h"
     15 
     16 static void i915_switcheroo_set_state(struct pci_dev *pdev,
     17 				      enum vga_switcheroo_state state)
     18 {
     19 	struct drm_i915_private *i915 = pdev_to_i915(pdev);
     20 	pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
     21 
     22 	if (!i915) {
     23 		dev_err(&pdev->dev, "DRM not initialized, aborting switch.\n");
     24 		return;
     25 	}
     26 
     27 	if (state == VGA_SWITCHEROO_ON) {
     28 		pr_info("switched on\n");
     29 		i915->drm.switch_power_state = DRM_SWITCH_POWER_CHANGING;
     30 		/* i915 resume handler doesn't set to D0 */
     31 		pci_set_power_state(pdev, PCI_D0);
     32 		i915_resume_switcheroo(i915);
     33 		i915->drm.switch_power_state = DRM_SWITCH_POWER_ON;
     34 	} else {
     35 		pr_info("switched off\n");
     36 		i915->drm.switch_power_state = DRM_SWITCH_POWER_CHANGING;
     37 		i915_suspend_switcheroo(i915, pmm);
     38 		i915->drm.switch_power_state = DRM_SWITCH_POWER_OFF;
     39 	}
     40 }
     41 
     42 static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
     43 {
     44 	struct drm_i915_private *i915 = pdev_to_i915(pdev);
     45 
     46 	/*
     47 	 * FIXME: open_count is protected by drm_global_mutex but that would lead to
     48 	 * locking inversion with the driver load path. And the access here is
     49 	 * completely racy anyway. So don't bother with locking for now.
     50 	 */
     51 	return i915 && i915->drm.open_count == 0;
     52 }
     53 
     54 static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
     55 	.set_gpu_state = i915_switcheroo_set_state,
     56 	.reprobe = NULL,
     57 	.can_switch = i915_switcheroo_can_switch,
     58 };
     59 
     60 int i915_switcheroo_register(struct drm_i915_private *i915)
     61 {
     62 	struct pci_dev *pdev = i915->drm.pdev;
     63 
     64 	return vga_switcheroo_register_client(pdev, &i915_switcheroo_ops, false);
     65 }
     66 
     67 void i915_switcheroo_unregister(struct drm_i915_private *i915)
     68 {
     69 	struct pci_dev *pdev = i915->drm.pdev;
     70 
     71 	vga_switcheroo_unregister_client(pdev);
     72 }
     73