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@xxxxxxxxxx> --- .../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(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/driverif.h b/drivers/gpu/drm/nouveau/include/nvif/driverif.h index e1d3ccc2128c..49db239f1156 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/driverif.h +++ b/drivers/gpu/drm/nouveau/include/nvif/driverif.h @@ -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 { diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/pci.h b/drivers/gpu/drm/nouveau/include/nvkm/core/pci.h index 7444c4d59e09..a1e9ee6da44e 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/pci.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/pci.h @@ -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, diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index b9c43fe552c0..da3120258527 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -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) { diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.h b/drivers/gpu/drm/nouveau/nouveau_acpi.h index a7fac1f7a73d..be1b218cb921 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.h +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.h @@ -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; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 52c4c3f58799..580849b78231 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -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; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index c2014a29891c..b44f0d408ccc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -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; diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c index 1f5ccec025d7..cb5cd4b93fdf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vga.c +++ b/drivers/gpu/drm/nouveau/nouveau_vga.c @@ -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) { diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.h b/drivers/gpu/drm/nouveau/nouveau_vga.h index 951a83f984dd..119b39cfbbcc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vga.h +++ b/drivers/gpu/drm/nouveau/nouveau_vga.h @@ -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 diff --git a/drivers/gpu/drm/nouveau/nvkm/device/acpi.c b/drivers/gpu/drm/nouveau/nvkm/device/acpi.c index 2bead7e879a5..cbaad3ea10eb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/device/acpi.c +++ b/drivers/gpu/drm/nouveau/nvkm/device/acpi.c @@ -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 } -- 2.44.0