@@ -2,6 +2,7 @@
#ifndef __NVIF_DRIVERIF_H__
#define __NVIF_DRIVERIF_H__
#include <drm/display/drm_dp.h>
+#include <linux/vga_switcheroo.h>
struct nvif_event_priv;
struct nvif_client_priv;
@@ -36,6 +37,12 @@ struct nvif_event_impl {
struct nvif_driver_func {
enum nvif_event_stat (*event)(u64 token, void *repv, u32 repc);
+
+ struct nvif_driver_func_switcheroo {
+ bool (*can_switch)(const struct nvif_driver_func *);
+ void (*set_state)(const struct nvif_driver_func *, enum vga_switcheroo_state);
+ void (*reprobe)(const struct nvif_driver_func *);
+ } switcheroo;
};
struct nvif_driver {
@@ -7,6 +7,8 @@ struct nvkm_device_pci {
struct nvkm_device device;
struct pci_dev *pdev;
bool suspend;
+
+ struct dev_pm_domain vga_pm_domain;
};
int nvkm_device_pci_new(struct pci_dev *, const char *cfg, const char *dbg,
@@ -8,14 +8,6 @@
#include "nouveau_drv.h"
#include "nouveau_acpi.h"
-bool nouveau_is_optimus(void) {
- return nouveau_dsm_priv.optimus_detected;
-}
-
-bool nouveau_is_v1_dsm(void) {
- return nouveau_dsm_priv.dsm_detected;
-}
-
void *
nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
{
@@ -5,16 +5,12 @@
#define ROM_BIOS_PAGE 4096
#if defined(CONFIG_ACPI) && defined(CONFIG_X86)
-bool nouveau_is_optimus(void);
-bool nouveau_is_v1_dsm(void);
#include <device/acpi.h>
static inline void nouveau_switcheroo_optimus_dsm(void) { nvkm_acpi_switcheroo_set_powerdown(); }
void *nouveau_acpi_edid(struct drm_device *, struct drm_connector *);
bool nouveau_acpi_video_backlight_use_native(void);
void nouveau_acpi_video_register_backlight(void);
#else
-static inline bool nouveau_is_optimus(void) { return false; };
-static inline bool nouveau_is_v1_dsm(void) { return false; };
static inline void nouveau_switcheroo_optimus_dsm(void) {}
static inline void *nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) { return NULL; }
static inline bool nouveau_acpi_video_backlight_use_native(void) { return true; }
@@ -505,7 +505,6 @@ nouveau_drm_device_fini(struct nouveau_drm *drm)
nouveau_bios_takedown(dev);
nouveau_ttm_fini(drm);
- nouveau_vga_fini(drm);
/*
* There may be existing clients from as-yet unclosed files. For now,
@@ -556,8 +555,6 @@ nouveau_drm_device_init(struct nouveau_drm *drm)
if (drm->device.impl->chipset == 0xc1)
nvif_mask(&drm->device, 0x00088080, 0x00000800, 0x00000000);
- nouveau_vga_init(drm);
-
ret = nouveau_ttm_init(drm);
if (ret)
goto fail_ttm;
@@ -608,7 +605,6 @@ nouveau_drm_device_init(struct nouveau_drm *drm)
fail_bios:
nouveau_ttm_fini(drm);
fail_ttm:
- nouveau_vga_fini(drm);
nouveau_cli_fini(&drm->cli);
fail_wq:
destroy_workqueue(drm->sched_wq);
@@ -650,6 +646,7 @@ nouveau_drm_device_new(const struct drm_driver *drm_driver, struct device *paren
drm->nvkm = device;
drm->driver = nouveau_driver;
+ drm->driver.switcheroo = nouveau_switcheroo;
device->cfgopt = nouveau_config;
device->dbgopt = nouveau_debug;
@@ -295,8 +295,6 @@ struct nouveau_drm {
/* led management */
struct nouveau_led *led;
- struct dev_pm_domain vga_pm_domain;
-
struct nouveau_svm *svm;
struct nouveau_dmem *dmem;
@@ -8,41 +8,35 @@
#include "nouveau_vga.h"
static void
-nouveau_switcheroo_set_state(struct pci_dev *pdev,
- enum vga_switcheroo_state state)
+nouveau_switcheroo_set_state(const struct nvif_driver_func *driver, enum vga_switcheroo_state state)
{
- struct nouveau_drm *drm = pci_get_drvdata(pdev);
- struct drm_device *dev = drm->dev;
-
- if ((nouveau_is_optimus() || nouveau_is_v1_dsm()) && state == VGA_SWITCHEROO_OFF)
- return;
+ struct drm_device *dev = container_of(driver, struct nouveau_drm, driver)->dev;
if (state == VGA_SWITCHEROO_ON) {
pr_err("VGA switcheroo: switched nouveau on\n");
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
- nouveau_pmops_resume(&pdev->dev);
+ nouveau_pmops_resume(dev->dev);
dev->switch_power_state = DRM_SWITCH_POWER_ON;
} else {
pr_err("VGA switcheroo: switched nouveau off\n");
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
- nouveau_switcheroo_optimus_dsm();
- nouveau_pmops_suspend(&pdev->dev);
+ nouveau_pmops_suspend(dev->dev);
dev->switch_power_state = DRM_SWITCH_POWER_OFF;
}
}
static void
-nouveau_switcheroo_reprobe(struct pci_dev *pdev)
+nouveau_switcheroo_reprobe(const struct nvif_driver_func *driver)
{
- struct nouveau_drm *drm = pci_get_drvdata(pdev);
+ struct nouveau_drm *drm = container_of(driver, struct nouveau_drm, driver);
drm_fb_helper_output_poll_changed(drm->dev);
}
static bool
-nouveau_switcheroo_can_switch(struct pci_dev *pdev)
+nouveau_switcheroo_can_switch(const struct nvif_driver_func *driver)
{
- struct nouveau_drm *drm = pci_get_drvdata(pdev);
+ struct nouveau_drm *drm = container_of(driver, struct nouveau_drm, driver);
/*
* FIXME: open_count is protected by drm_global_mutex but that would lead to
@@ -52,56 +46,13 @@ nouveau_switcheroo_can_switch(struct pci_dev *pdev)
return atomic_read(&drm->dev->open_count) == 0;
}
-static const struct vga_switcheroo_client_ops
-nouveau_switcheroo_ops = {
- .set_gpu_state = nouveau_switcheroo_set_state,
+const struct nvif_driver_func_switcheroo
+nouveau_switcheroo = {
+ .set_state = nouveau_switcheroo_set_state,
.reprobe = nouveau_switcheroo_reprobe,
.can_switch = nouveau_switcheroo_can_switch,
};
-void
-nouveau_vga_init(struct nouveau_drm *drm)
-{
- struct drm_device *dev = drm->dev;
- bool runtime = nouveau_pmops_runtime(dev->dev);
- struct pci_dev *pdev;
-
- /* only relevant for PCI devices */
- if (!dev_is_pci(dev->dev))
- return;
- pdev = to_pci_dev(dev->dev);
-
- /* don't register Thunderbolt eGPU with vga_switcheroo */
- if (pci_is_thunderbolt_attached(pdev))
- return;
-
- vga_switcheroo_register_client(pdev, &nouveau_switcheroo_ops, runtime);
-
- if (runtime && nouveau_is_v1_dsm() && !nouveau_is_optimus())
- vga_switcheroo_init_domain_pm_ops(drm->dev->dev, &drm->vga_pm_domain);
-}
-
-void
-nouveau_vga_fini(struct nouveau_drm *drm)
-{
- struct drm_device *dev = drm->dev;
- bool runtime = nouveau_pmops_runtime(dev->dev);
- struct pci_dev *pdev;
-
- /* only relevant for PCI devices */
- if (!dev_is_pci(dev->dev))
- return;
- pdev = to_pci_dev(dev->dev);
-
- if (pci_is_thunderbolt_attached(pdev))
- return;
-
- vga_switcheroo_unregister_client(pdev);
- if (runtime && nouveau_is_v1_dsm() && !nouveau_is_optimus())
- vga_switcheroo_fini_domain_pm_ops(drm->dev->dev);
-}
-
-
void
nouveau_vga_lastclose(struct drm_device *dev)
{
@@ -2,8 +2,7 @@
#ifndef __NOUVEAU_VGA_H__
#define __NOUVEAU_VGA_H__
-void nouveau_vga_init(struct nouveau_drm *);
-void nouveau_vga_fini(struct nouveau_drm *);
+extern const struct nvif_driver_func_switcheroo nouveau_switcheroo;
void nouveau_vga_lastclose(struct drm_device *dev);
#endif
@@ -23,9 +23,11 @@
*/
#include "acpi.h"
-#include <core/device.h>
+#include <core/pci.h>
#include <subdev/clk.h>
+#include <nvif/driverif.h>
+
#include <linux/mxm-wmi.h>
#include <linux/vga_switcheroo.h>
@@ -189,6 +191,48 @@ static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switchero
return 0;
}
+#include "nouveau_drv.h"
+#include "nouveau_acpi.h"
+
+static void
+nvkm_acpi_switcheroo_reprobe(struct pci_dev *pdev)
+{
+ struct nvkm_device *device = ((struct nouveau_drm *)pci_get_drvdata(pdev))->nvkm;
+
+ device->driver->switcheroo.reprobe(device->driver);
+}
+
+static void
+nvkm_acpi_switcheroo_set_state(struct pci_dev *pdev,
+ enum vga_switcheroo_state state)
+{
+ struct nvkm_device *device = ((struct nouveau_drm *)pci_get_drvdata(pdev))->nvkm;
+
+ if (state == VGA_SWITCHEROO_OFF) {
+ if (nouveau_dsm_priv.dsm_detected || nouveau_dsm_priv.optimus_detected)
+ return;
+
+ nvkm_acpi_switcheroo_set_powerdown();
+ }
+
+ device->driver->switcheroo.set_state(device->driver, state);
+}
+
+static bool
+nvkm_acpi_switcheroo_can_switch(struct pci_dev *pdev)
+{
+ struct nvkm_device *device = ((struct nouveau_drm *)pci_get_drvdata(pdev))->nvkm;
+
+ return device->driver->switcheroo.can_switch(device->driver);
+}
+
+static const struct vga_switcheroo_client_ops
+nvkm_acpi_switcheroo_ops = {
+ .can_switch = nvkm_acpi_switcheroo_can_switch,
+ .set_gpu_state = nvkm_acpi_switcheroo_set_state,
+ .reprobe = nvkm_acpi_switcheroo_reprobe,
+};
+
static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id)
{
if (!nouveau_dsm_priv.dsm_detected)
@@ -380,16 +424,53 @@ nvkm_acpi_ntfy(struct notifier_block *nb, unsigned long val, void *data)
void
nvkm_acpi_fini(struct nvkm_device *device)
{
+ struct nvkm_device_pci *pdev;
+
+ if (!device->func->pci)
+ return;
+
+ pdev = device->func->pci(device);
+ (void)pdev;
+
#ifdef CONFIG_ACPI
unregister_acpi_notifier(&device->acpi.nb);
#endif
+
+#ifdef CONFIG_VGA_SWITCHEROO
+ if (pci_is_thunderbolt_attached(pdev->pdev))
+ return;
+
+ vga_switcheroo_unregister_client(pdev->pdev);
+ if (device->runpm == NVKM_DEVICE_RUNPM_V1)
+ vga_switcheroo_fini_domain_pm_ops(device->dev);
+#endif
}
void
nvkm_acpi_init(struct nvkm_device *device)
{
+ struct nvkm_device_pci *pdev;
+
+ if (!device->func->pci)
+ return;
+
+ pdev = device->func->pci(device);
+ (void)pdev;
+
#ifdef CONFIG_ACPI
device->acpi.nb.notifier_call = nvkm_acpi_ntfy;
register_acpi_notifier(&device->acpi.nb);
#endif
+
+#ifdef CONFIG_VGA_SWITCHEROO
+ /* don't register Thunderbolt eGPU with vga_switcheroo */
+ if (pci_is_thunderbolt_attached(pdev->pdev))
+ return;
+
+ vga_switcheroo_register_client(pdev->pdev, &nvkm_acpi_switcheroo_ops,
+ device->runpm != NVKM_DEVICE_RUNPM_NONE);
+
+ if (device->runpm == NVKM_DEVICE_RUNPM_V1)
+ vga_switcheroo_init_domain_pm_ops(device->dev, &pdev->vga_pm_domain);
+#endif
}
The DRM driver needs to do things in response to vga_switcheroo_client callbacks, so this move isn't a direct copy+paste. 3 new callbacks are added to nvif_driver_func, which are basically the same as the switcheroo callbacks, except NVKM handles all the PCI/ACPI parts, and calls into the DRM driver for the rest. Signed-off-by: Ben Skeggs <bskeggs@nvidia.com> --- .../gpu/drm/nouveau/include/nvif/driverif.h | 7 ++ .../gpu/drm/nouveau/include/nvkm/core/pci.h | 2 + drivers/gpu/drm/nouveau/nouveau_acpi.c | 8 -- drivers/gpu/drm/nouveau/nouveau_acpi.h | 4 - drivers/gpu/drm/nouveau/nouveau_drm.c | 5 +- drivers/gpu/drm/nouveau/nouveau_drv.h | 2 - drivers/gpu/drm/nouveau/nouveau_vga.c | 71 +++------------- drivers/gpu/drm/nouveau/nouveau_vga.h | 3 +- drivers/gpu/drm/nouveau/nvkm/device/acpi.c | 83 ++++++++++++++++++- 9 files changed, 104 insertions(+), 81 deletions(-)