On Wed, Mar 9, 2016 at 7:14 AM, Dave Airlie <airlied@xxxxxxxxx> wrote: > From: Dave Airlie <airlied@xxxxxxxxxx> > > Windows 10 seems to have standardised power control for the > optimus/powerxpress laptops using PR3 power resource hooks. > > I'm not sure this is definitely the correct place to be > doing this, but it works for me here. > > The ACPI device for the GPU I have is \_SB_.PCI0.PEG_.VID_ > but the power resource hooks are on \_SB_.PCI0.PEG_, so > this patch creates a new power domain to turn the GPU > device parent off using standard ACPI calls. > > Signed-off-by: Dave Airlie <airlied@xxxxxxxxxx> > --- > drivers/gpu/vga/vga_switcheroo.c | 54 +++++++++++++++++++++++++++++++++++++++- > include/linux/vga_switcheroo.h | 3 ++- > 2 files changed, 55 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c > index 665ab9f..be32cb2 100644 > --- a/drivers/gpu/vga/vga_switcheroo.c > +++ b/drivers/gpu/vga/vga_switcheroo.c > @@ -42,7 +42,7 @@ > #include <linux/uaccess.h> > #include <linux/vgaarb.h> > #include <linux/vga_switcheroo.h> > - > +#include <linux/acpi.h> > /** > * DOC: Overview > * > @@ -997,3 +997,55 @@ vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, > return -EINVAL; > } > EXPORT_SYMBOL(vga_switcheroo_init_domain_pm_optimus_hdmi_audio); > + > +/* With Windows 10 the runtime suspend/resume can use power > + resources on the parent device */ > +static int vga_acpi_switcheroo_runtime_suspend(struct device *dev) > +{ > + struct pci_dev *pdev = to_pci_dev(dev); > + int ret; > + struct acpi_device *adev; > + > + ret = dev->bus->pm->runtime_suspend(dev); > + if (ret) > + return ret; > + > + ret = acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev); You can use ACPI_COMPANION(&pdev->dev) for that. > + if (!ret) > + acpi_device_set_power(adev->parent, ACPI_STATE_D3_COLD); Won't that mess up with the PM of the parent? Or do we know that the parent won't do its own PM? > + return 0; > +} > + > +static int vga_acpi_switcheroo_runtime_resume(struct device *dev) > +{ > + struct pci_dev *pdev = to_pci_dev(dev); > + struct acpi_device *adev; > + int ret; > + > + ret = acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev); ACPI_COMPANION(&pdev->dev) here too? > + if (!ret) > + acpi_device_set_power(adev->parent, ACPI_STATE_D0); > + ret = dev->bus->pm->runtime_resume(dev); > + if (ret) > + return ret; > + > + return 0; > +} > + > +int vga_switcheroo_init_parent_pr3_ops(struct device *dev, > + struct dev_pm_domain *domain) > + > +{ > + /* copy over all the bus versions */ > + if (dev->bus && dev->bus->pm) { > + domain->ops = *dev->bus->pm; > + domain->ops.runtime_suspend = vga_acpi_switcheroo_runtime_suspend; > + domain->ops.runtime_resume = vga_acpi_switcheroo_runtime_resume; > + > + dev_pm_domain_set(dev, domain); > + return 0; > + } > + dev_pm_domain_set(dev, NULL); > + return -EINVAL; > +} > +EXPORT_SYMBOL(vga_switcheroo_init_parent_pr3_ops); > diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h > index 69e1d4a1..5ce0cbe 100644 > --- a/include/linux/vga_switcheroo.h > +++ b/include/linux/vga_switcheroo.h > @@ -144,6 +144,7 @@ void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo > 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); > int vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, struct dev_pm_domain *domain); > +int vga_switcheroo_init_parent_pr3_ops(struct device *dev, struct dev_pm_domain *domain); > #else > > static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {} > @@ -163,6 +164,6 @@ static inline void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum > 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 int vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, struct dev_pm_domain *domain) { return -EINVAL; } > - > +static inline int vga_switcheroo_init_parent_pr3_ops(struct device *dev, struct dev_pm_domain *domain) { return -EINVAL; } > #endif > #endif /* _LINUX_VGA_SWITCHEROO_H_ */ > -- > 2.5.0 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-acpi" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel