194580299SBen Skeggs /* 294580299SBen Skeggs * Copyright 2012 Red Hat Inc. 394580299SBen Skeggs * 494580299SBen Skeggs * Permission is hereby granted, free of charge, to any person obtaining a 594580299SBen Skeggs * copy of this software and associated documentation files (the "Software"), 694580299SBen Skeggs * to deal in the Software without restriction, including without limitation 794580299SBen Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense, 894580299SBen Skeggs * and/or sell copies of the Software, and to permit persons to whom the 994580299SBen Skeggs * Software is furnished to do so, subject to the following conditions: 1094580299SBen Skeggs * 1194580299SBen Skeggs * The above copyright notice and this permission notice shall be included in 1294580299SBen Skeggs * all copies or substantial portions of the Software. 1394580299SBen Skeggs * 1494580299SBen Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1594580299SBen Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1694580299SBen Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1794580299SBen Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 1894580299SBen Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1994580299SBen Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2094580299SBen Skeggs * OTHER DEALINGS IN THE SOFTWARE. 2194580299SBen Skeggs * 2294580299SBen Skeggs * Authors: Ben Skeggs 2394580299SBen Skeggs */ 2494580299SBen Skeggs 25c5fd936eSLukas Wunner #include <linux/delay.h> 2694580299SBen Skeggs #include <linux/module.h> 2794580299SBen Skeggs #include <linux/pci.h> 285addcf0aSDave Airlie #include <linux/pm_runtime.h> 295addcf0aSDave Airlie #include <linux/vga_switcheroo.h> 30c7d8b782SJason Gunthorpe #include <linux/mmu_notifier.h> 31f158936bSJim Cromie #include <linux/dynamic_debug.h> 32fdb751efSBen Skeggs 336848c291SThomas Zimmermann #include <drm/drm_aperture.h> 346a2d2ddfSJavier Martinez Canillas #include <drm/drm_drv.h> 354e291f2fSDave Airlie #include <drm/drm_fbdev_generic.h> 364c398f50SThomas Zimmermann #include <drm/drm_gem_ttm_helper.h> 37690ae20cSSam Ravnborg #include <drm/drm_ioctl.h> 38690ae20cSSam Ravnborg #include <drm/drm_vblank.h> 39fdb751efSBen Skeggs 40ebb945a9SBen Skeggs #include <core/gpuobj.h> 41c33e05a1SIlia Mirkin #include <core/option.h> 427974dd1bSBen Skeggs #include <core/pci.h> 437974dd1bSBen Skeggs #include <core/tegra.h> 4494580299SBen Skeggs 4504b88677SBen Skeggs #include <nvif/driver.h> 46a7cf0180SBen Skeggs #include <nvif/fifo.h> 470d2bdf2bSBen Skeggs #include <nvif/push006c.h> 4837e1c45aSBen Skeggs #include <nvif/user.h> 4904b88677SBen Skeggs 50923bc416SBen Skeggs #include <nvif/class.h> 51845f2725SBen Skeggs #include <nvif/cl0002.h> 52538b269bSBen Skeggs 534dc28134SBen Skeggs #include "nouveau_drv.h" 54ebb945a9SBen Skeggs #include "nouveau_dma.h" 5577145f1cSBen Skeggs #include "nouveau_ttm.h" 5677145f1cSBen Skeggs #include "nouveau_gem.h" 5777145f1cSBen Skeggs #include "nouveau_vga.h" 588d021d71SMartin Peres #include "nouveau_led.h" 59b9ed919fSBen Skeggs #include "nouveau_hwmon.h" 6077145f1cSBen Skeggs #include "nouveau_acpi.h" 6177145f1cSBen Skeggs #include "nouveau_bios.h" 6277145f1cSBen Skeggs #include "nouveau_ioctl.h" 63ebb945a9SBen Skeggs #include "nouveau_abi16.h" 64ebb945a9SBen Skeggs #include "nouveau_fence.h" 6533b903e8SMarcin Slusarz #include "nouveau_debugfs.h" 6627111a23SBen Skeggs #include "nouveau_usif.h" 67703fa264SPierre Moreau #include "nouveau_connector.h" 68055a65d5SAlexandre Courbot #include "nouveau_platform.h" 69eeaf06acSBen Skeggs #include "nouveau_svm.h" 705be73b69SJérôme Glisse #include "nouveau_dmem.h" 71ebb945a9SBen Skeggs 72f158936bSJim Cromie DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, 73f158936bSJim Cromie "DRM_UT_CORE", 74f158936bSJim Cromie "DRM_UT_DRIVER", 75f158936bSJim Cromie "DRM_UT_KMS", 76f158936bSJim Cromie "DRM_UT_PRIME", 77f158936bSJim Cromie "DRM_UT_ATOMIC", 78f158936bSJim Cromie "DRM_UT_VBL", 79f158936bSJim Cromie "DRM_UT_STATE", 80f158936bSJim Cromie "DRM_UT_LEASE", 81f158936bSJim Cromie "DRM_UT_DP", 82f158936bSJim Cromie "DRM_UT_DRMRES"); 83f158936bSJim Cromie 8494580299SBen Skeggs MODULE_PARM_DESC(config, "option string to pass to driver core"); 8594580299SBen Skeggs static char *nouveau_config; 8694580299SBen Skeggs module_param_named(config, nouveau_config, charp, 0400); 8794580299SBen Skeggs 8894580299SBen Skeggs MODULE_PARM_DESC(debug, "debug string to pass to driver core"); 8994580299SBen Skeggs static char *nouveau_debug; 9094580299SBen Skeggs module_param_named(debug, nouveau_debug, charp, 0400); 9194580299SBen Skeggs 92ebb945a9SBen Skeggs MODULE_PARM_DESC(noaccel, "disable kernel/abi16 acceleration"); 93ebb945a9SBen Skeggs static int nouveau_noaccel = 0; 94ebb945a9SBen Skeggs module_param_named(noaccel, nouveau_noaccel, int, 0400); 95ebb945a9SBen Skeggs 969430738dSBen Skeggs MODULE_PARM_DESC(modeset, "enable driver (default: auto, " 979430738dSBen Skeggs "0 = disabled, 1 = enabled, 2 = headless)"); 989430738dSBen Skeggs int nouveau_modeset = -1; 9977145f1cSBen Skeggs module_param_named(modeset, nouveau_modeset, int, 0400); 10077145f1cSBen Skeggs 101eb493fbcSLyude Paul MODULE_PARM_DESC(atomic, "Expose atomic ioctl (default: disabled)"); 102eb493fbcSLyude Paul static int nouveau_atomic = 0; 103eb493fbcSLyude Paul module_param_named(atomic, nouveau_atomic, int, 0400); 104eb493fbcSLyude Paul 1055addcf0aSDave Airlie MODULE_PARM_DESC(runpm, "disable (0), force enable (1), optimus only default (-1)"); 106321f5c5fSBen Skeggs static int nouveau_runtime_pm = -1; 1075addcf0aSDave Airlie module_param_named(runpm, nouveau_runtime_pm, int, 0400); 1085addcf0aSDave Airlie 109915b4d11SDavid Herrmann static struct drm_driver driver_stub; 110915b4d11SDavid Herrmann static struct drm_driver driver_pci; 111915b4d11SDavid Herrmann static struct drm_driver driver_platform; 11277145f1cSBen Skeggs 11394580299SBen Skeggs static u64 114420b9469SAlexandre Courbot nouveau_pci_name(struct pci_dev *pdev) 11594580299SBen Skeggs { 11694580299SBen Skeggs u64 name = (u64)pci_domain_nr(pdev->bus) << 32; 11794580299SBen Skeggs name |= pdev->bus->number << 16; 11894580299SBen Skeggs name |= PCI_SLOT(pdev->devfn) << 8; 11994580299SBen Skeggs return name | PCI_FUNC(pdev->devfn); 12094580299SBen Skeggs } 12194580299SBen Skeggs 122420b9469SAlexandre Courbot static u64 123420b9469SAlexandre Courbot nouveau_platform_name(struct platform_device *platformdev) 124420b9469SAlexandre Courbot { 125420b9469SAlexandre Courbot return platformdev->id; 126420b9469SAlexandre Courbot } 127420b9469SAlexandre Courbot 128420b9469SAlexandre Courbot static u64 129420b9469SAlexandre Courbot nouveau_name(struct drm_device *dev) 130420b9469SAlexandre Courbot { 1314c0d42f7SThomas Zimmermann if (dev_is_pci(dev->dev)) 1324c0d42f7SThomas Zimmermann return nouveau_pci_name(to_pci_dev(dev->dev)); 133420b9469SAlexandre Courbot else 13476adb460SLaurent Pinchart return nouveau_platform_name(to_platform_device(dev->dev)); 135420b9469SAlexandre Courbot } 136420b9469SAlexandre Courbot 137814a2324SBen Skeggs static inline bool 13811e451e7SBen Skeggs nouveau_cli_work_ready(struct dma_fence *fence) 139814a2324SBen Skeggs { 140*c8a5d5eaSDave Airlie bool ret = true; 141*c8a5d5eaSDave Airlie 142*c8a5d5eaSDave Airlie spin_lock_irq(fence->lock); 143*c8a5d5eaSDave Airlie if (!dma_fence_is_signaled_locked(fence)) 144*c8a5d5eaSDave Airlie ret = false; 145*c8a5d5eaSDave Airlie spin_unlock_irq(fence->lock); 146*c8a5d5eaSDave Airlie 147*c8a5d5eaSDave Airlie if (ret == true) 148814a2324SBen Skeggs dma_fence_put(fence); 149*c8a5d5eaSDave Airlie return ret; 150814a2324SBen Skeggs } 151814a2324SBen Skeggs 152814a2324SBen Skeggs static void 15311e451e7SBen Skeggs nouveau_cli_work(struct work_struct *w) 154814a2324SBen Skeggs { 15511e451e7SBen Skeggs struct nouveau_cli *cli = container_of(w, typeof(*cli), work); 156814a2324SBen Skeggs struct nouveau_cli_work *work, *wtmp; 157814a2324SBen Skeggs mutex_lock(&cli->lock); 158814a2324SBen Skeggs list_for_each_entry_safe(work, wtmp, &cli->worker, head) { 15911e451e7SBen Skeggs if (!work->fence || nouveau_cli_work_ready(work->fence)) { 160814a2324SBen Skeggs list_del(&work->head); 161814a2324SBen Skeggs work->func(work); 162814a2324SBen Skeggs } 163814a2324SBen Skeggs } 164814a2324SBen Skeggs mutex_unlock(&cli->lock); 165814a2324SBen Skeggs } 166814a2324SBen Skeggs 167814a2324SBen Skeggs static void 168814a2324SBen Skeggs nouveau_cli_work_fence(struct dma_fence *fence, struct dma_fence_cb *cb) 169814a2324SBen Skeggs { 170814a2324SBen Skeggs struct nouveau_cli_work *work = container_of(cb, typeof(*work), cb); 171814a2324SBen Skeggs schedule_work(&work->cli->work); 172814a2324SBen Skeggs } 173814a2324SBen Skeggs 174814a2324SBen Skeggs void 175814a2324SBen Skeggs nouveau_cli_work_queue(struct nouveau_cli *cli, struct dma_fence *fence, 176814a2324SBen Skeggs struct nouveau_cli_work *work) 177814a2324SBen Skeggs { 178814a2324SBen Skeggs work->fence = dma_fence_get(fence); 179814a2324SBen Skeggs work->cli = cli; 180814a2324SBen Skeggs mutex_lock(&cli->lock); 181814a2324SBen Skeggs list_add_tail(&work->head, &cli->worker); 182814a2324SBen Skeggs if (dma_fence_add_callback(fence, &work->cb, nouveau_cli_work_fence)) 183814a2324SBen Skeggs nouveau_cli_work_fence(fence, &work->cb); 184b26a2319SBen Skeggs mutex_unlock(&cli->lock); 185814a2324SBen Skeggs } 186814a2324SBen Skeggs 187814a2324SBen Skeggs static void 18820d8a88eSBen Skeggs nouveau_cli_fini(struct nouveau_cli *cli) 18994580299SBen Skeggs { 19011e451e7SBen Skeggs /* All our channels are dead now, which means all the fences they 19111e451e7SBen Skeggs * own are signalled, and all callback functions have been called. 19211e451e7SBen Skeggs * 19311e451e7SBen Skeggs * So, after flushing the workqueue, there should be nothing left. 19411e451e7SBen Skeggs */ 19511e451e7SBen Skeggs flush_work(&cli->work); 19611e451e7SBen Skeggs WARN_ON(!list_empty(&cli->worker)); 19711e451e7SBen Skeggs 19827111a23SBen Skeggs usif_client_fini(cli); 199bfe91afaSBen Skeggs nouveau_vmm_fini(&cli->svm); 20024e8375bSBen Skeggs nouveau_vmm_fini(&cli->vmm); 201b495396cSBen Skeggs nvif_mmu_dtor(&cli->mmu); 202bd21080eSBen Skeggs nvif_device_dtor(&cli->device); 203cb7e88e7SBen Skeggs mutex_lock(&cli->drm->master.lock); 2046db25fb1SBen Skeggs nvif_client_dtor(&cli->base); 205cb7e88e7SBen Skeggs mutex_unlock(&cli->drm->master.lock); 20620d8a88eSBen Skeggs } 20720d8a88eSBen Skeggs 20820d8a88eSBen Skeggs static int 20920d8a88eSBen Skeggs nouveau_cli_init(struct nouveau_drm *drm, const char *sname, 21020d8a88eSBen Skeggs struct nouveau_cli *cli) 21120d8a88eSBen Skeggs { 21201670a79SBen Skeggs static const struct nvif_mclass 2137f507624SBen Skeggs mems[] = { 2147f507624SBen Skeggs { NVIF_CLASS_MEM_GF100, -1 }, 2157f507624SBen Skeggs { NVIF_CLASS_MEM_NV50 , -1 }, 2167f507624SBen Skeggs { NVIF_CLASS_MEM_NV04 , -1 }, 2177f507624SBen Skeggs {} 2187f507624SBen Skeggs }; 2197f507624SBen Skeggs static const struct nvif_mclass 22001670a79SBen Skeggs mmus[] = { 22101670a79SBen Skeggs { NVIF_CLASS_MMU_GF100, -1 }, 22201670a79SBen Skeggs { NVIF_CLASS_MMU_NV50 , -1 }, 22301670a79SBen Skeggs { NVIF_CLASS_MMU_NV04 , -1 }, 22401670a79SBen Skeggs {} 22501670a79SBen Skeggs }; 22696da0bcdSBen Skeggs static const struct nvif_mclass 22796da0bcdSBen Skeggs vmms[] = { 22896da0bcdSBen Skeggs { NVIF_CLASS_VMM_GP100, -1 }, 22996da0bcdSBen Skeggs { NVIF_CLASS_VMM_GM200, -1 }, 23096da0bcdSBen Skeggs { NVIF_CLASS_VMM_GF100, -1 }, 23196da0bcdSBen Skeggs { NVIF_CLASS_VMM_NV50 , -1 }, 23296da0bcdSBen Skeggs { NVIF_CLASS_VMM_NV04 , -1 }, 23396da0bcdSBen Skeggs {} 23496da0bcdSBen Skeggs }; 23520d8a88eSBen Skeggs u64 device = nouveau_name(drm->dev); 23620d8a88eSBen Skeggs int ret; 23720d8a88eSBen Skeggs 23820d8a88eSBen Skeggs snprintf(cli->name, sizeof(cli->name), "%s", sname); 239e75c091bSBen Skeggs cli->drm = drm; 24020d8a88eSBen Skeggs mutex_init(&cli->mutex); 24120d8a88eSBen Skeggs usif_client_init(cli); 24220d8a88eSBen Skeggs 243814a2324SBen Skeggs INIT_WORK(&cli->work, nouveau_cli_work); 244814a2324SBen Skeggs INIT_LIST_HEAD(&cli->worker); 245cb7e88e7SBen Skeggs mutex_init(&cli->lock); 246cb7e88e7SBen Skeggs 247cb7e88e7SBen Skeggs if (cli == &drm->master) { 24820d8a88eSBen Skeggs ret = nvif_driver_init(NULL, nouveau_config, nouveau_debug, 24920d8a88eSBen Skeggs cli->name, device, &cli->base); 25080e60973SBen Skeggs } else { 251cb7e88e7SBen Skeggs mutex_lock(&drm->master.lock); 2526db25fb1SBen Skeggs ret = nvif_client_ctor(&drm->master.base, cli->name, device, 25380e60973SBen Skeggs &cli->base); 254cb7e88e7SBen Skeggs mutex_unlock(&drm->master.lock); 25580e60973SBen Skeggs } 25620d8a88eSBen Skeggs if (ret) { 257a43b16ddSBen Skeggs NV_PRINTK(err, cli, "Client allocation failed: %d\n", ret); 25820d8a88eSBen Skeggs goto done; 25920d8a88eSBen Skeggs } 26020d8a88eSBen Skeggs 261bd21080eSBen Skeggs ret = nvif_device_ctor(&cli->base.object, "drmDevice", 0, NV_DEVICE, 2621167c6bcSBen Skeggs &(struct nv_device_v0) { 2631167c6bcSBen Skeggs .device = ~0, 264148a8653SBen Skeggs .priv = true, 2651167c6bcSBen Skeggs }, sizeof(struct nv_device_v0), 2661167c6bcSBen Skeggs &cli->device); 2671167c6bcSBen Skeggs if (ret) { 268a43b16ddSBen Skeggs NV_PRINTK(err, cli, "Device allocation failed: %d\n", ret); 2691167c6bcSBen Skeggs goto done; 2701167c6bcSBen Skeggs } 2711167c6bcSBen Skeggs 27201670a79SBen Skeggs ret = nvif_mclass(&cli->device.object, mmus); 27301670a79SBen Skeggs if (ret < 0) { 274a43b16ddSBen Skeggs NV_PRINTK(err, cli, "No supported MMU class\n"); 27501670a79SBen Skeggs goto done; 27601670a79SBen Skeggs } 27701670a79SBen Skeggs 278b495396cSBen Skeggs ret = nvif_mmu_ctor(&cli->device.object, "drmMmu", mmus[ret].oclass, 279b495396cSBen Skeggs &cli->mmu); 28001670a79SBen Skeggs if (ret) { 281a43b16ddSBen Skeggs NV_PRINTK(err, cli, "MMU allocation failed: %d\n", ret); 28201670a79SBen Skeggs goto done; 28301670a79SBen Skeggs } 28401670a79SBen Skeggs 28596da0bcdSBen Skeggs ret = nvif_mclass(&cli->mmu.object, vmms); 28696da0bcdSBen Skeggs if (ret < 0) { 287a43b16ddSBen Skeggs NV_PRINTK(err, cli, "No supported VMM class\n"); 28896da0bcdSBen Skeggs goto done; 28996da0bcdSBen Skeggs } 29096da0bcdSBen Skeggs 29196da0bcdSBen Skeggs ret = nouveau_vmm_init(cli, vmms[ret].oclass, &cli->vmm); 29296da0bcdSBen Skeggs if (ret) { 293a43b16ddSBen Skeggs NV_PRINTK(err, cli, "VMM allocation failed: %d\n", ret); 29496da0bcdSBen Skeggs goto done; 29596da0bcdSBen Skeggs } 29696da0bcdSBen Skeggs 2977f507624SBen Skeggs ret = nvif_mclass(&cli->mmu.object, mems); 2987f507624SBen Skeggs if (ret < 0) { 299a43b16ddSBen Skeggs NV_PRINTK(err, cli, "No supported MEM class\n"); 3007f507624SBen Skeggs goto done; 3017f507624SBen Skeggs } 3027f507624SBen Skeggs 3037f507624SBen Skeggs cli->mem = &mems[ret]; 3047f507624SBen Skeggs return 0; 30520d8a88eSBen Skeggs done: 30620d8a88eSBen Skeggs if (ret) 30720d8a88eSBen Skeggs nouveau_cli_fini(cli); 30820d8a88eSBen Skeggs return ret; 30994580299SBen Skeggs } 31094580299SBen Skeggs 311ebb945a9SBen Skeggs static void 312f0eee9aeSBen Skeggs nouveau_accel_ce_fini(struct nouveau_drm *drm) 313f0eee9aeSBen Skeggs { 314f0eee9aeSBen Skeggs nouveau_channel_idle(drm->cechan); 3159ac596a4SBen Skeggs nvif_object_dtor(&drm->ttm.copy); 316f0eee9aeSBen Skeggs nouveau_channel_del(&drm->cechan); 317f0eee9aeSBen Skeggs } 318f0eee9aeSBen Skeggs 319f0eee9aeSBen Skeggs static void 320f0eee9aeSBen Skeggs nouveau_accel_ce_init(struct nouveau_drm *drm) 321f0eee9aeSBen Skeggs { 322f0eee9aeSBen Skeggs struct nvif_device *device = &drm->client.device; 3236de12538SBen Skeggs u64 runm; 324f0eee9aeSBen Skeggs int ret = 0; 325f0eee9aeSBen Skeggs 326f0eee9aeSBen Skeggs /* Allocate channel that has access to a (preferably async) copy 327f0eee9aeSBen Skeggs * engine, to use for TTM buffer moves. 328f0eee9aeSBen Skeggs */ 3296de12538SBen Skeggs runm = nvif_fifo_runlist_ce(device); 3306de12538SBen Skeggs if (!runm) { 3316de12538SBen Skeggs NV_DEBUG(drm, "no ce runlist\n"); 3326de12538SBen Skeggs return; 333f0eee9aeSBen Skeggs } 334f0eee9aeSBen Skeggs 3356de12538SBen Skeggs ret = nouveau_channel_new(drm, device, false, runm, NvDmaFB, NvDmaTT, &drm->cechan); 336f0eee9aeSBen Skeggs if (ret) 337f0eee9aeSBen Skeggs NV_ERROR(drm, "failed to create ce channel, %d\n", ret); 338f0eee9aeSBen Skeggs } 339f0eee9aeSBen Skeggs 340f0eee9aeSBen Skeggs static void 341f0eee9aeSBen Skeggs nouveau_accel_gr_fini(struct nouveau_drm *drm) 342ebb945a9SBen Skeggs { 343fbd58ebdSBen Skeggs nouveau_channel_idle(drm->channel); 3449ac596a4SBen Skeggs nvif_object_dtor(&drm->ntfy); 345f027f491SBen Skeggs nvkm_gpuobj_del(&drm->notify); 346fbd58ebdSBen Skeggs nouveau_channel_del(&drm->channel); 347f0eee9aeSBen Skeggs } 348fbd58ebdSBen Skeggs 349f0eee9aeSBen Skeggs static void 350f0eee9aeSBen Skeggs nouveau_accel_gr_init(struct nouveau_drm *drm) 351f0eee9aeSBen Skeggs { 352f0eee9aeSBen Skeggs struct nvif_device *device = &drm->client.device; 3536de12538SBen Skeggs u64 runm; 354f0eee9aeSBen Skeggs int ret; 355fbd58ebdSBen Skeggs 356f0eee9aeSBen Skeggs /* Allocate channel that has access to the graphics engine. */ 3576de12538SBen Skeggs runm = nvif_fifo_runlist(device, NV_DEVICE_HOST_RUNLIST_ENGINES_GR); 3586de12538SBen Skeggs if (!runm) { 3596de12538SBen Skeggs NV_DEBUG(drm, "no gr runlist\n"); 3606de12538SBen Skeggs return; 361f0eee9aeSBen Skeggs } 362f0eee9aeSBen Skeggs 3636de12538SBen Skeggs ret = nouveau_channel_new(drm, device, false, runm, NvDmaFB, NvDmaTT, &drm->channel); 364f0eee9aeSBen Skeggs if (ret) { 365f0eee9aeSBen Skeggs NV_ERROR(drm, "failed to create kernel channel, %d\n", ret); 366f0eee9aeSBen Skeggs nouveau_accel_gr_fini(drm); 367f0eee9aeSBen Skeggs return; 368f0eee9aeSBen Skeggs } 369f0eee9aeSBen Skeggs 370f0eee9aeSBen Skeggs /* A SW class is used on pre-NV50 HW to assist with handling the 371f0eee9aeSBen Skeggs * synchronisation of page flips, as well as to implement fences 372f0eee9aeSBen Skeggs * on TNT/TNT2 HW that lacks any kind of support in host. 373f0eee9aeSBen Skeggs */ 3742bf00037SBen Skeggs if (!drm->channel->nvsw.client && device->info.family < NV_DEVICE_INFO_V0_TESLA) { 3759ac596a4SBen Skeggs ret = nvif_object_ctor(&drm->channel->user, "drmNvsw", 3769ac596a4SBen Skeggs NVDRM_NVSW, nouveau_abi16_swclass(drm), 3772bf00037SBen Skeggs NULL, 0, &drm->channel->nvsw); 378f0eee9aeSBen Skeggs if (ret == 0) { 3790d2bdf2bSBen Skeggs struct nvif_push *push = drm->channel->chan.push; 3800d2bdf2bSBen Skeggs ret = PUSH_WAIT(push, 2); 3810d2bdf2bSBen Skeggs if (ret == 0) 3820d2bdf2bSBen Skeggs PUSH_NVSQ(push, NV_SW, 0x0000, drm->channel->nvsw.handle); 383f0eee9aeSBen Skeggs } 384f0eee9aeSBen Skeggs 385f0eee9aeSBen Skeggs if (ret) { 386f0eee9aeSBen Skeggs NV_ERROR(drm, "failed to allocate sw class, %d\n", ret); 387f0eee9aeSBen Skeggs nouveau_accel_gr_fini(drm); 388f0eee9aeSBen Skeggs return; 389f0eee9aeSBen Skeggs } 390f0eee9aeSBen Skeggs } 391f0eee9aeSBen Skeggs 392f0eee9aeSBen Skeggs /* NvMemoryToMemoryFormat requires a notifier ctxdma for some reason, 393f0eee9aeSBen Skeggs * even if notification is never requested, so, allocate a ctxdma on 394f0eee9aeSBen Skeggs * any GPU where it's possible we'll end up using M2MF for BO moves. 395f0eee9aeSBen Skeggs */ 396f0eee9aeSBen Skeggs if (device->info.family < NV_DEVICE_INFO_V0_FERMI) { 397f0eee9aeSBen Skeggs ret = nvkm_gpuobj_new(nvxx_device(device), 32, 0, false, NULL, 398f0eee9aeSBen Skeggs &drm->notify); 399f0eee9aeSBen Skeggs if (ret) { 400f0eee9aeSBen Skeggs NV_ERROR(drm, "failed to allocate notifier, %d\n", ret); 401f0eee9aeSBen Skeggs nouveau_accel_gr_fini(drm); 402f0eee9aeSBen Skeggs return; 403f0eee9aeSBen Skeggs } 404f0eee9aeSBen Skeggs 4059ac596a4SBen Skeggs ret = nvif_object_ctor(&drm->channel->user, "drmM2mfNtfy", 4069ac596a4SBen Skeggs NvNotify0, NV_DMA_IN_MEMORY, 407f0eee9aeSBen Skeggs &(struct nv_dma_v0) { 408f0eee9aeSBen Skeggs .target = NV_DMA_V0_TARGET_VRAM, 409f0eee9aeSBen Skeggs .access = NV_DMA_V0_ACCESS_RDWR, 410f0eee9aeSBen Skeggs .start = drm->notify->addr, 411f0eee9aeSBen Skeggs .limit = drm->notify->addr + 31 412f0eee9aeSBen Skeggs }, sizeof(struct nv_dma_v0), 413f0eee9aeSBen Skeggs &drm->ntfy); 414f0eee9aeSBen Skeggs if (ret) { 415f0eee9aeSBen Skeggs nouveau_accel_gr_fini(drm); 416f0eee9aeSBen Skeggs return; 417f0eee9aeSBen Skeggs } 418f0eee9aeSBen Skeggs } 419f0eee9aeSBen Skeggs } 420f0eee9aeSBen Skeggs 421f0eee9aeSBen Skeggs static void 422f0eee9aeSBen Skeggs nouveau_accel_fini(struct nouveau_drm *drm) 423f0eee9aeSBen Skeggs { 424f0eee9aeSBen Skeggs nouveau_accel_ce_fini(drm); 425f0eee9aeSBen Skeggs nouveau_accel_gr_fini(drm); 426ebb945a9SBen Skeggs if (drm->fence) 427ebb945a9SBen Skeggs nouveau_fence(drm)->dtor(drm); 428eb39c613SBen Skeggs nouveau_channels_fini(drm); 429ebb945a9SBen Skeggs } 430ebb945a9SBen Skeggs 431ebb945a9SBen Skeggs static void 432ebb945a9SBen Skeggs nouveau_accel_init(struct nouveau_drm *drm) 433ebb945a9SBen Skeggs { 4341167c6bcSBen Skeggs struct nvif_device *device = &drm->client.device; 43541a63406SBen Skeggs struct nvif_sclass *sclass; 43641a63406SBen Skeggs int ret, i, n; 437ebb945a9SBen Skeggs 438967e7bdeSBen Skeggs if (nouveau_noaccel) 439ebb945a9SBen Skeggs return; 440ebb945a9SBen Skeggs 441f0eee9aeSBen Skeggs /* Initialise global support for channels, and synchronisation. */ 442eb47db4fSBen Skeggs ret = nouveau_channels_init(drm); 443eb47db4fSBen Skeggs if (ret) 444eb47db4fSBen Skeggs return; 445eb47db4fSBen Skeggs 446967e7bdeSBen Skeggs /*XXX: this is crap, but the fence/channel stuff is a little 447967e7bdeSBen Skeggs * backwards in some places. this will be fixed. 448967e7bdeSBen Skeggs */ 44941a63406SBen Skeggs ret = n = nvif_object_sclass_get(&device->object, &sclass); 450967e7bdeSBen Skeggs if (ret < 0) 451967e7bdeSBen Skeggs return; 452967e7bdeSBen Skeggs 45341a63406SBen Skeggs for (ret = -ENOSYS, i = 0; i < n; i++) { 45441a63406SBen Skeggs switch (sclass[i].oclass) { 455bbf8906bSBen Skeggs case NV03_CHANNEL_DMA: 456967e7bdeSBen Skeggs ret = nv04_fence_create(drm); 457967e7bdeSBen Skeggs break; 458bbf8906bSBen Skeggs case NV10_CHANNEL_DMA: 459967e7bdeSBen Skeggs ret = nv10_fence_create(drm); 460967e7bdeSBen Skeggs break; 461bbf8906bSBen Skeggs case NV17_CHANNEL_DMA: 462bbf8906bSBen Skeggs case NV40_CHANNEL_DMA: 463967e7bdeSBen Skeggs ret = nv17_fence_create(drm); 464967e7bdeSBen Skeggs break; 465bbf8906bSBen Skeggs case NV50_CHANNEL_GPFIFO: 466967e7bdeSBen Skeggs ret = nv50_fence_create(drm); 467967e7bdeSBen Skeggs break; 468bbf8906bSBen Skeggs case G82_CHANNEL_GPFIFO: 469967e7bdeSBen Skeggs ret = nv84_fence_create(drm); 470967e7bdeSBen Skeggs break; 471bbf8906bSBen Skeggs case FERMI_CHANNEL_GPFIFO: 472bbf8906bSBen Skeggs case KEPLER_CHANNEL_GPFIFO_A: 47363f8c9b7SBen Skeggs case KEPLER_CHANNEL_GPFIFO_B: 474a1020afeSBen Skeggs case MAXWELL_CHANNEL_GPFIFO_A: 475e8ff9794SBen Skeggs case PASCAL_CHANNEL_GPFIFO_A: 47637e1c45aSBen Skeggs case VOLTA_CHANNEL_GPFIFO_A: 477641d0b30SBen Skeggs case TURING_CHANNEL_GPFIFO_A: 4787f4f35eaSBen Skeggs case AMPERE_CHANNEL_GPFIFO_A: 47949b2dfc0SBen Skeggs case AMPERE_CHANNEL_GPFIFO_B: 480967e7bdeSBen Skeggs ret = nvc0_fence_create(drm); 481967e7bdeSBen Skeggs break; 482967e7bdeSBen Skeggs default: 483967e7bdeSBen Skeggs break; 484967e7bdeSBen Skeggs } 485967e7bdeSBen Skeggs } 486967e7bdeSBen Skeggs 48741a63406SBen Skeggs nvif_object_sclass_put(&sclass); 488ebb945a9SBen Skeggs if (ret) { 489ebb945a9SBen Skeggs NV_ERROR(drm, "failed to initialise sync subsystem, %d\n", ret); 490ebb945a9SBen Skeggs nouveau_accel_fini(drm); 491ebb945a9SBen Skeggs return; 492ebb945a9SBen Skeggs } 493ebb945a9SBen Skeggs 494f0eee9aeSBen Skeggs /* Volta requires access to a doorbell register for kickoff. */ 495f0eee9aeSBen Skeggs if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_VOLTA) { 49664a0f59aSBen Skeggs ret = nvif_user_ctor(device, "drmUsermode"); 49749981046SBen Skeggs if (ret) 498ebb945a9SBen Skeggs return; 499ebb945a9SBen Skeggs } 500ebb945a9SBen Skeggs 501f0eee9aeSBen Skeggs /* Allocate channels we need to support various functions. */ 502f0eee9aeSBen Skeggs nouveau_accel_gr_init(drm); 503f0eee9aeSBen Skeggs nouveau_accel_ce_init(drm); 50469a6146dSBen Skeggs 505f0eee9aeSBen Skeggs /* Initialise accelerated TTM buffer moves. */ 50649981046SBen Skeggs nouveau_bo_move_init(drm); 507ebb945a9SBen Skeggs } 508ebb945a9SBen Skeggs 5093e176fd0SBen Skeggs static void __printf(2, 3) 5103e176fd0SBen Skeggs nouveau_drm_errorf(struct nvif_object *object, const char *fmt, ...) 5113e176fd0SBen Skeggs { 5123e176fd0SBen Skeggs struct nouveau_drm *drm = container_of(object->parent, typeof(*drm), parent); 5133e176fd0SBen Skeggs struct va_format vaf; 5143e176fd0SBen Skeggs va_list va; 5153e176fd0SBen Skeggs 5163e176fd0SBen Skeggs va_start(va, fmt); 5173e176fd0SBen Skeggs vaf.fmt = fmt; 5183e176fd0SBen Skeggs vaf.va = &va; 5193e176fd0SBen Skeggs NV_ERROR(drm, "%pV", &vaf); 5203e176fd0SBen Skeggs va_end(va); 5213e176fd0SBen Skeggs } 5223e176fd0SBen Skeggs 5233e176fd0SBen Skeggs static void __printf(2, 3) 5243e176fd0SBen Skeggs nouveau_drm_debugf(struct nvif_object *object, const char *fmt, ...) 5253e176fd0SBen Skeggs { 5263e176fd0SBen Skeggs struct nouveau_drm *drm = container_of(object->parent, typeof(*drm), parent); 5273e176fd0SBen Skeggs struct va_format vaf; 5283e176fd0SBen Skeggs va_list va; 5293e176fd0SBen Skeggs 5303e176fd0SBen Skeggs va_start(va, fmt); 5313e176fd0SBen Skeggs vaf.fmt = fmt; 5323e176fd0SBen Skeggs vaf.va = &va; 5333e176fd0SBen Skeggs NV_DEBUG(drm, "%pV", &vaf); 5343e176fd0SBen Skeggs va_end(va); 5353e176fd0SBen Skeggs } 5363e176fd0SBen Skeggs 5373e176fd0SBen Skeggs static const struct nvif_parent_func 5383e176fd0SBen Skeggs nouveau_parent = { 5393e176fd0SBen Skeggs .debugf = nouveau_drm_debugf, 5403e176fd0SBen Skeggs .errorf = nouveau_drm_errorf, 5413e176fd0SBen Skeggs }; 5423e176fd0SBen Skeggs 5435b8a43aeSMarcin Slusarz static int 544cfea88a4SLyude Paul nouveau_drm_device_init(struct drm_device *dev) 54594580299SBen Skeggs { 54694580299SBen Skeggs struct nouveau_drm *drm; 54794580299SBen Skeggs int ret; 54894580299SBen Skeggs 54920d8a88eSBen Skeggs if (!(drm = kzalloc(sizeof(*drm), GFP_KERNEL))) 55020d8a88eSBen Skeggs return -ENOMEM; 55120d8a88eSBen Skeggs dev->dev_private = drm; 55220d8a88eSBen Skeggs drm->dev = dev; 55320d8a88eSBen Skeggs 5543e176fd0SBen Skeggs nvif_parent_ctor(&nouveau_parent, &drm->parent); 5553e176fd0SBen Skeggs drm->master.base.object.parent = &drm->parent; 5563e176fd0SBen Skeggs 557cb7e88e7SBen Skeggs ret = nouveau_cli_init(drm, "DRM-master", &drm->master); 558cb7e88e7SBen Skeggs if (ret) 559c4cee69aSLyude Paul goto fail_alloc; 560cb7e88e7SBen Skeggs 56120d8a88eSBen Skeggs ret = nouveau_cli_init(drm, "DRM", &drm->client); 56294580299SBen Skeggs if (ret) 563c4cee69aSLyude Paul goto fail_master; 56494580299SBen Skeggs 565989aa5b7SBen Skeggs nvxx_client(&drm->client.base)->debug = 566be83cd4eSBen Skeggs nvkm_dbgopt(nouveau_debug, "DRM"); 56777145f1cSBen Skeggs 56894580299SBen Skeggs INIT_LIST_HEAD(&drm->clients); 569abae9164SJeremy Cline mutex_init(&drm->clients_lock); 570ebb945a9SBen Skeggs spin_lock_init(&drm->tile.lock); 57194580299SBen Skeggs 57277145f1cSBen Skeggs /* workaround an odd issue on nvc1 by disabling the device's 57377145f1cSBen Skeggs * nosnoop capability. hopefully won't cause issues until a 57477145f1cSBen Skeggs * better fix is found - assuming there is one... 57577145f1cSBen Skeggs */ 5761167c6bcSBen Skeggs if (drm->client.device.info.chipset == 0xc1) 5771167c6bcSBen Skeggs nvif_mask(&drm->client.device.object, 0x00088080, 0x00000800, 0x00000000); 578ebb945a9SBen Skeggs 57977145f1cSBen Skeggs nouveau_vga_init(drm); 580cb75d97eSBen Skeggs 581ebb945a9SBen Skeggs ret = nouveau_ttm_init(drm); 58294580299SBen Skeggs if (ret) 58377145f1cSBen Skeggs goto fail_ttm; 58494580299SBen Skeggs 58577145f1cSBen Skeggs ret = nouveau_bios_init(dev); 586ebb945a9SBen Skeggs if (ret) 58777145f1cSBen Skeggs goto fail_bios; 58877145f1cSBen Skeggs 589d7f9bb65SBen Skeggs nouveau_accel_init(drm); 590d7f9bb65SBen Skeggs 59177145f1cSBen Skeggs ret = nouveau_display_create(dev); 59277145f1cSBen Skeggs if (ret) 59377145f1cSBen Skeggs goto fail_dispctor; 59477145f1cSBen Skeggs 59577145f1cSBen Skeggs if (dev->mode_config.num_crtc) { 5960f9976ddSBen Skeggs ret = nouveau_display_init(dev, false, false); 59777145f1cSBen Skeggs if (ret) 59877145f1cSBen Skeggs goto fail_dispinit; 59977145f1cSBen Skeggs } 60077145f1cSBen Skeggs 601b126a200SKarol Herbst nouveau_debugfs_init(drm); 602b9ed919fSBen Skeggs nouveau_hwmon_init(dev); 603eeaf06acSBen Skeggs nouveau_svm_init(drm); 6045be73b69SJérôme Glisse nouveau_dmem_init(drm); 6058d021d71SMartin Peres nouveau_led_init(dev); 6065addcf0aSDave Airlie 6078fa4338aSBen Skeggs if (nouveau_pmops_runtime()) { 6085addcf0aSDave Airlie pm_runtime_use_autosuspend(dev->dev); 6095addcf0aSDave Airlie pm_runtime_set_autosuspend_delay(dev->dev, 5000); 6105addcf0aSDave Airlie pm_runtime_set_active(dev->dev); 6115addcf0aSDave Airlie pm_runtime_allow(dev->dev); 6125addcf0aSDave Airlie pm_runtime_mark_last_busy(dev->dev); 6135addcf0aSDave Airlie pm_runtime_put(dev->dev); 6145addcf0aSDave Airlie } 6157326ead9SLyude Paul 61694580299SBen Skeggs return 0; 61794580299SBen Skeggs 61877145f1cSBen Skeggs fail_dispinit: 61977145f1cSBen Skeggs nouveau_display_destroy(dev); 62077145f1cSBen Skeggs fail_dispctor: 621d7f9bb65SBen Skeggs nouveau_accel_fini(drm); 62277145f1cSBen Skeggs nouveau_bios_takedown(dev); 62377145f1cSBen Skeggs fail_bios: 624ebb945a9SBen Skeggs nouveau_ttm_fini(drm); 62577145f1cSBen Skeggs fail_ttm: 62677145f1cSBen Skeggs nouveau_vga_fini(drm); 62720d8a88eSBen Skeggs nouveau_cli_fini(&drm->client); 628c4cee69aSLyude Paul fail_master: 629cb7e88e7SBen Skeggs nouveau_cli_fini(&drm->master); 630c4cee69aSLyude Paul fail_alloc: 6313e176fd0SBen Skeggs nvif_parent_dtor(&drm->parent); 63220d8a88eSBen Skeggs kfree(drm); 63394580299SBen Skeggs return ret; 63494580299SBen Skeggs } 63594580299SBen Skeggs 63611b3c20bSGabriel Krisman Bertazi static void 637cfea88a4SLyude Paul nouveau_drm_device_fini(struct drm_device *dev) 63894580299SBen Skeggs { 639f55aaf63SJeremy Cline struct nouveau_cli *cli, *temp_cli; 64077145f1cSBen Skeggs struct nouveau_drm *drm = nouveau_drm(dev); 64194580299SBen Skeggs 6428fa4338aSBen Skeggs if (nouveau_pmops_runtime()) { 6435addcf0aSDave Airlie pm_runtime_get_sync(dev->dev); 64455c868a3SLukas Wunner pm_runtime_forbid(dev->dev); 645c1b16b45SLukas Wunner } 646c1b16b45SLukas Wunner 6478d021d71SMartin Peres nouveau_led_fini(dev); 6485be73b69SJérôme Glisse nouveau_dmem_fini(drm); 649eeaf06acSBen Skeggs nouveau_svm_fini(drm); 650b9ed919fSBen Skeggs nouveau_hwmon_fini(dev); 651b126a200SKarol Herbst nouveau_debugfs_fini(drm); 65277145f1cSBen Skeggs 6539430738dSBen Skeggs if (dev->mode_config.num_crtc) 6542f7ca781SLyude Paul nouveau_display_fini(dev, false, false); 65577145f1cSBen Skeggs nouveau_display_destroy(dev); 65677145f1cSBen Skeggs 657d7f9bb65SBen Skeggs nouveau_accel_fini(drm); 65877145f1cSBen Skeggs nouveau_bios_takedown(dev); 65994580299SBen Skeggs 660ebb945a9SBen Skeggs nouveau_ttm_fini(drm); 66177145f1cSBen Skeggs nouveau_vga_fini(drm); 662cb75d97eSBen Skeggs 663f55aaf63SJeremy Cline /* 664f55aaf63SJeremy Cline * There may be existing clients from as-yet unclosed files. For now, 665f55aaf63SJeremy Cline * clean them up here rather than deferring until the file is closed, 666f55aaf63SJeremy Cline * but this likely not correct if we want to support hot-unplugging 667f55aaf63SJeremy Cline * properly. 668f55aaf63SJeremy Cline */ 669f55aaf63SJeremy Cline mutex_lock(&drm->clients_lock); 670f55aaf63SJeremy Cline list_for_each_entry_safe(cli, temp_cli, &drm->clients, head) { 671f55aaf63SJeremy Cline list_del(&cli->head); 672f55aaf63SJeremy Cline mutex_lock(&cli->mutex); 673f55aaf63SJeremy Cline if (cli->abi16) 674f55aaf63SJeremy Cline nouveau_abi16_fini(cli->abi16); 675f55aaf63SJeremy Cline mutex_unlock(&cli->mutex); 676f55aaf63SJeremy Cline nouveau_cli_fini(cli); 677f55aaf63SJeremy Cline kfree(cli); 678f55aaf63SJeremy Cline } 679f55aaf63SJeremy Cline mutex_unlock(&drm->clients_lock); 680f55aaf63SJeremy Cline 68120d8a88eSBen Skeggs nouveau_cli_fini(&drm->client); 682cb7e88e7SBen Skeggs nouveau_cli_fini(&drm->master); 6833e176fd0SBen Skeggs nvif_parent_dtor(&drm->parent); 684abae9164SJeremy Cline mutex_destroy(&drm->clients_lock); 68520d8a88eSBen Skeggs kfree(drm); 68694580299SBen Skeggs } 68794580299SBen Skeggs 688434fdb51SKarol Herbst /* 689434fdb51SKarol Herbst * On some Intel PCIe bridge controllers doing a 690434fdb51SKarol Herbst * D0 -> D3hot -> D3cold -> D0 sequence causes Nvidia GPUs to not reappear. 691434fdb51SKarol Herbst * Skipping the intermediate D3hot step seems to make it work again. This is 692434fdb51SKarol Herbst * probably caused by not meeting the expectation the involved AML code has 693434fdb51SKarol Herbst * when the GPU is put into D3hot state before invoking it. 694434fdb51SKarol Herbst * 695434fdb51SKarol Herbst * This leads to various manifestations of this issue: 696434fdb51SKarol Herbst * - AML code execution to power on the GPU hits an infinite loop (as the 697434fdb51SKarol Herbst * code waits on device memory to change). 698434fdb51SKarol Herbst * - kernel crashes, as all PCI reads return -1, which most code isn't able 699434fdb51SKarol Herbst * to handle well enough. 700434fdb51SKarol Herbst * 701434fdb51SKarol Herbst * In all cases dmesg will contain at least one line like this: 702434fdb51SKarol Herbst * 'nouveau 0000:01:00.0: Refused to change power state, currently in D3' 703434fdb51SKarol Herbst * followed by a lot of nouveau timeouts. 704434fdb51SKarol Herbst * 705434fdb51SKarol Herbst * In the \_SB.PCI0.PEG0.PG00._OFF code deeper down writes bit 0x80 to the not 706434fdb51SKarol Herbst * documented PCI config space register 0x248 of the Intel PCIe bridge 707434fdb51SKarol Herbst * controller (0x1901) in order to change the state of the PCIe link between 708434fdb51SKarol Herbst * the PCIe port and the GPU. There are alternative code paths using other 709434fdb51SKarol Herbst * registers, which seem to work fine (executed pre Windows 8): 710434fdb51SKarol Herbst * - 0xbc bit 0x20 (publicly available documentation claims 'reserved') 711434fdb51SKarol Herbst * - 0xb0 bit 0x10 (link disable) 712434fdb51SKarol Herbst * Changing the conditions inside the firmware by poking into the relevant 713434fdb51SKarol Herbst * addresses does resolve the issue, but it seemed to be ACPI private memory 714434fdb51SKarol Herbst * and not any device accessible memory at all, so there is no portable way of 715434fdb51SKarol Herbst * changing the conditions. 716434fdb51SKarol Herbst * On a XPS 9560 that means bits [0,3] on \CPEX need to be cleared. 717434fdb51SKarol Herbst * 718434fdb51SKarol Herbst * The only systems where this behavior can be seen are hybrid graphics laptops 719434fdb51SKarol Herbst * with a secondary Nvidia Maxwell, Pascal or Turing GPU. It's unclear whether 720434fdb51SKarol Herbst * this issue only occurs in combination with listed Intel PCIe bridge 721434fdb51SKarol Herbst * controllers and the mentioned GPUs or other devices as well. 722434fdb51SKarol Herbst * 723434fdb51SKarol Herbst * documentation on the PCIe bridge controller can be found in the 724434fdb51SKarol Herbst * "7th Generation Intel® Processor Families for H Platforms Datasheet Volume 2" 725434fdb51SKarol Herbst * Section "12 PCI Express* Controller (x16) Registers" 726434fdb51SKarol Herbst */ 727434fdb51SKarol Herbst 728434fdb51SKarol Herbst static void quirk_broken_nv_runpm(struct pci_dev *pdev) 729434fdb51SKarol Herbst { 730434fdb51SKarol Herbst struct drm_device *dev = pci_get_drvdata(pdev); 731434fdb51SKarol Herbst struct nouveau_drm *drm = nouveau_drm(dev); 732434fdb51SKarol Herbst struct pci_dev *bridge = pci_upstream_bridge(pdev); 733434fdb51SKarol Herbst 734434fdb51SKarol Herbst if (!bridge || bridge->vendor != PCI_VENDOR_ID_INTEL) 735434fdb51SKarol Herbst return; 736434fdb51SKarol Herbst 737434fdb51SKarol Herbst switch (bridge->device) { 738434fdb51SKarol Herbst case 0x1901: 739434fdb51SKarol Herbst drm->old_pm_cap = pdev->pm_cap; 740434fdb51SKarol Herbst pdev->pm_cap = 0; 741434fdb51SKarol Herbst NV_INFO(drm, "Disabling PCI power management to avoid bug\n"); 742434fdb51SKarol Herbst break; 743434fdb51SKarol Herbst } 744434fdb51SKarol Herbst } 745434fdb51SKarol Herbst 746cfea88a4SLyude Paul static int nouveau_drm_probe(struct pci_dev *pdev, 747cfea88a4SLyude Paul const struct pci_device_id *pent) 748cfea88a4SLyude Paul { 749cfea88a4SLyude Paul struct nvkm_device *device; 750cfea88a4SLyude Paul struct drm_device *drm_dev; 751cfea88a4SLyude Paul int ret; 752cfea88a4SLyude Paul 753cfea88a4SLyude Paul if (vga_switcheroo_client_probe_defer(pdev)) 754cfea88a4SLyude Paul return -EPROBE_DEFER; 755cfea88a4SLyude Paul 756cfea88a4SLyude Paul /* We need to check that the chipset is supported before booting 757cfea88a4SLyude Paul * fbdev off the hardware, as there's no way to put it back. 758cfea88a4SLyude Paul */ 759a2ac09a0SBen Skeggs ret = nvkm_device_pci_new(pdev, nouveau_config, "error", 760a2ac09a0SBen Skeggs true, false, 0, &device); 761cfea88a4SLyude Paul if (ret) 762cfea88a4SLyude Paul return ret; 763cfea88a4SLyude Paul 764cfea88a4SLyude Paul nvkm_device_del(&device); 765cfea88a4SLyude Paul 766cfea88a4SLyude Paul /* Remove conflicting drivers (vesafb, efifb etc). */ 76797c9bfe3SThomas Zimmermann ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &driver_pci); 7682dd4d163SBen Skeggs if (ret) 7692dd4d163SBen Skeggs return ret; 770cfea88a4SLyude Paul 771cfea88a4SLyude Paul ret = nvkm_device_pci_new(pdev, nouveau_config, nouveau_debug, 772cfea88a4SLyude Paul true, true, ~0ULL, &device); 773cfea88a4SLyude Paul if (ret) 774cfea88a4SLyude Paul return ret; 775cfea88a4SLyude Paul 776cfea88a4SLyude Paul pci_set_master(pdev); 777cfea88a4SLyude Paul 778cfea88a4SLyude Paul if (nouveau_atomic) 779cfea88a4SLyude Paul driver_pci.driver_features |= DRIVER_ATOMIC; 780cfea88a4SLyude Paul 781cfea88a4SLyude Paul drm_dev = drm_dev_alloc(&driver_pci, &pdev->dev); 782cfea88a4SLyude Paul if (IS_ERR(drm_dev)) { 783cfea88a4SLyude Paul ret = PTR_ERR(drm_dev); 784cfea88a4SLyude Paul goto fail_nvkm; 785cfea88a4SLyude Paul } 786cfea88a4SLyude Paul 787cfea88a4SLyude Paul ret = pci_enable_device(pdev); 788cfea88a4SLyude Paul if (ret) 789cfea88a4SLyude Paul goto fail_drm; 790cfea88a4SLyude Paul 791cfea88a4SLyude Paul pci_set_drvdata(pdev, drm_dev); 792cfea88a4SLyude Paul 793cfea88a4SLyude Paul ret = nouveau_drm_device_init(drm_dev); 794cfea88a4SLyude Paul if (ret) 795cfea88a4SLyude Paul goto fail_pci; 796cfea88a4SLyude Paul 797cfea88a4SLyude Paul ret = drm_dev_register(drm_dev, pent->driver_data); 798cfea88a4SLyude Paul if (ret) 799cfea88a4SLyude Paul goto fail_drm_dev_init; 800cfea88a4SLyude Paul 8014a16dd9dSBen Skeggs if (nouveau_drm(drm_dev)->client.device.info.ram_size <= 32 * 1024 * 1024) 8024a16dd9dSBen Skeggs drm_fbdev_generic_setup(drm_dev, 8); 8034a16dd9dSBen Skeggs else 8044a16dd9dSBen Skeggs drm_fbdev_generic_setup(drm_dev, 32); 8054a16dd9dSBen Skeggs 806434fdb51SKarol Herbst quirk_broken_nv_runpm(pdev); 807cfea88a4SLyude Paul return 0; 808cfea88a4SLyude Paul 809cfea88a4SLyude Paul fail_drm_dev_init: 810cfea88a4SLyude Paul nouveau_drm_device_fini(drm_dev); 811cfea88a4SLyude Paul fail_pci: 812cfea88a4SLyude Paul pci_disable_device(pdev); 813cfea88a4SLyude Paul fail_drm: 814cfea88a4SLyude Paul drm_dev_put(drm_dev); 815cfea88a4SLyude Paul fail_nvkm: 816cfea88a4SLyude Paul nvkm_device_del(&device); 817cfea88a4SLyude Paul return ret; 818cfea88a4SLyude Paul } 819cfea88a4SLyude Paul 8208ba9ff11SAlexandre Courbot void 8218ba9ff11SAlexandre Courbot nouveau_drm_device_remove(struct drm_device *dev) 82294580299SBen Skeggs { 82377145f1cSBen Skeggs struct nouveau_drm *drm = nouveau_drm(dev); 824be83cd4eSBen Skeggs struct nvkm_client *client; 82576ecea5bSBen Skeggs struct nvkm_device *device; 82677145f1cSBen Skeggs 827aff2299eSJeremy Cline drm_dev_unplug(dev); 828cfea88a4SLyude Paul 829989aa5b7SBen Skeggs client = nvxx_client(&drm->client.base); 8304e7e62d6SBen Skeggs device = nvkm_device_find(client->device); 83177145f1cSBen Skeggs 832cfea88a4SLyude Paul nouveau_drm_device_fini(dev); 833cfea88a4SLyude Paul drm_dev_put(dev); 834e781dc8fSBen Skeggs nvkm_device_del(&device); 83594580299SBen Skeggs } 8368ba9ff11SAlexandre Courbot 8378ba9ff11SAlexandre Courbot static void 8388ba9ff11SAlexandre Courbot nouveau_drm_remove(struct pci_dev *pdev) 8398ba9ff11SAlexandre Courbot { 8408ba9ff11SAlexandre Courbot struct drm_device *dev = pci_get_drvdata(pdev); 841434fdb51SKarol Herbst struct nouveau_drm *drm = nouveau_drm(dev); 8428ba9ff11SAlexandre Courbot 843434fdb51SKarol Herbst /* revert our workaround */ 844434fdb51SKarol Herbst if (drm->old_pm_cap) 845434fdb51SKarol Herbst pdev->pm_cap = drm->old_pm_cap; 8468ba9ff11SAlexandre Courbot nouveau_drm_device_remove(dev); 847f1331ea8SThierry Reding pci_disable_device(pdev); 8488ba9ff11SAlexandre Courbot } 84994580299SBen Skeggs 850cd897837SMarcin Slusarz static int 85105c63c2fSDave Airlie nouveau_do_suspend(struct drm_device *dev, bool runtime) 85294580299SBen Skeggs { 85377145f1cSBen Skeggs struct nouveau_drm *drm = nouveau_drm(dev); 8544ce032d6SChristian König struct ttm_resource_manager *man; 85594580299SBen Skeggs int ret; 85694580299SBen Skeggs 857eeaf06acSBen Skeggs nouveau_svm_suspend(drm); 8585be73b69SJérôme Glisse nouveau_dmem_suspend(drm); 8598d021d71SMartin Peres nouveau_led_suspend(dev); 8608d021d71SMartin Peres 8616fbb702eSBen Skeggs if (dev->mode_config.num_crtc) { 8622d38a535SBen Skeggs NV_DEBUG(drm, "suspending display...\n"); 8636fbb702eSBen Skeggs ret = nouveau_display_suspend(dev, runtime); 86494580299SBen Skeggs if (ret) 86594580299SBen Skeggs return ret; 8669430738dSBen Skeggs } 86794580299SBen Skeggs 8682d38a535SBen Skeggs NV_DEBUG(drm, "evicting buffers...\n"); 8694ce032d6SChristian König 8704ce032d6SChristian König man = ttm_manager_type(&drm->ttm.bdev, TTM_PL_VRAM); 8714ce032d6SChristian König ttm_resource_manager_evict_all(&drm->ttm.bdev, man); 872ebb945a9SBen Skeggs 8732d38a535SBen Skeggs NV_DEBUG(drm, "waiting for kernel channels to go idle...\n"); 87481dff21bSBen Skeggs if (drm->cechan) { 87581dff21bSBen Skeggs ret = nouveau_channel_idle(drm->cechan); 87681dff21bSBen Skeggs if (ret) 877f3980dc5SIlia Mirkin goto fail_display; 87881dff21bSBen Skeggs } 87981dff21bSBen Skeggs 88081dff21bSBen Skeggs if (drm->channel) { 88181dff21bSBen Skeggs ret = nouveau_channel_idle(drm->channel); 88281dff21bSBen Skeggs if (ret) 883f3980dc5SIlia Mirkin goto fail_display; 88481dff21bSBen Skeggs } 88581dff21bSBen Skeggs 8862d38a535SBen Skeggs NV_DEBUG(drm, "suspending fence...\n"); 887ebb945a9SBen Skeggs if (drm->fence && nouveau_fence(drm)->suspend) { 888f3980dc5SIlia Mirkin if (!nouveau_fence(drm)->suspend(drm)) { 889f3980dc5SIlia Mirkin ret = -ENOMEM; 890f3980dc5SIlia Mirkin goto fail_display; 891f3980dc5SIlia Mirkin } 892ebb945a9SBen Skeggs } 893ebb945a9SBen Skeggs 8942d38a535SBen Skeggs NV_DEBUG(drm, "suspending object tree...\n"); 895cb7e88e7SBen Skeggs ret = nvif_client_suspend(&drm->master.base); 89694580299SBen Skeggs if (ret) 89794580299SBen Skeggs goto fail_client; 89894580299SBen Skeggs 89994580299SBen Skeggs return 0; 90094580299SBen Skeggs 90194580299SBen Skeggs fail_client: 902f3980dc5SIlia Mirkin if (drm->fence && nouveau_fence(drm)->resume) 903f3980dc5SIlia Mirkin nouveau_fence(drm)->resume(drm); 904f3980dc5SIlia Mirkin 905f3980dc5SIlia Mirkin fail_display: 9069430738dSBen Skeggs if (dev->mode_config.num_crtc) { 9072d38a535SBen Skeggs NV_DEBUG(drm, "resuming display...\n"); 9086fbb702eSBen Skeggs nouveau_display_resume(dev, runtime); 9099430738dSBen Skeggs } 91094580299SBen Skeggs return ret; 91194580299SBen Skeggs } 91294580299SBen Skeggs 913cd897837SMarcin Slusarz static int 9146fbb702eSBen Skeggs nouveau_do_resume(struct drm_device *dev, bool runtime) 9152d8b9ccbSDave Airlie { 91630df16b9STobias Klausmann int ret = 0; 9172d8b9ccbSDave Airlie struct nouveau_drm *drm = nouveau_drm(dev); 9182d8b9ccbSDave Airlie 9192d38a535SBen Skeggs NV_DEBUG(drm, "resuming object tree...\n"); 92030df16b9STobias Klausmann ret = nvif_client_resume(&drm->master.base); 92130df16b9STobias Klausmann if (ret) { 92230df16b9STobias Klausmann NV_ERROR(drm, "Client resume failed with error: %d\n", ret); 92330df16b9STobias Klausmann return ret; 92430df16b9STobias Klausmann } 92594580299SBen Skeggs 9262d38a535SBen Skeggs NV_DEBUG(drm, "resuming fence...\n"); 92781dff21bSBen Skeggs if (drm->fence && nouveau_fence(drm)->resume) 92881dff21bSBen Skeggs nouveau_fence(drm)->resume(drm); 92981dff21bSBen Skeggs 93077145f1cSBen Skeggs nouveau_run_vbios_init(dev); 93177145f1cSBen Skeggs 9329430738dSBen Skeggs if (dev->mode_config.num_crtc) { 9332d38a535SBen Skeggs NV_DEBUG(drm, "resuming display...\n"); 9346fbb702eSBen Skeggs nouveau_display_resume(dev, runtime); 9359430738dSBen Skeggs } 9365addcf0aSDave Airlie 9378d021d71SMartin Peres nouveau_led_resume(dev); 9385be73b69SJérôme Glisse nouveau_dmem_resume(drm); 939eeaf06acSBen Skeggs nouveau_svm_resume(drm); 94077145f1cSBen Skeggs return 0; 94194580299SBen Skeggs } 94294580299SBen Skeggs 9437bb6d442SBen Skeggs int 9447bb6d442SBen Skeggs nouveau_pmops_suspend(struct device *dev) 9457bb6d442SBen Skeggs { 9467bb6d442SBen Skeggs struct pci_dev *pdev = to_pci_dev(dev); 9477bb6d442SBen Skeggs struct drm_device *drm_dev = pci_get_drvdata(pdev); 9487bb6d442SBen Skeggs int ret; 9497bb6d442SBen Skeggs 9507bb6d442SBen Skeggs if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF || 9517bb6d442SBen Skeggs drm_dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF) 9527bb6d442SBen Skeggs return 0; 9537bb6d442SBen Skeggs 9547bb6d442SBen Skeggs ret = nouveau_do_suspend(drm_dev, false); 9557bb6d442SBen Skeggs if (ret) 9567bb6d442SBen Skeggs return ret; 9577bb6d442SBen Skeggs 9587bb6d442SBen Skeggs pci_save_state(pdev); 9597bb6d442SBen Skeggs pci_disable_device(pdev); 9607bb6d442SBen Skeggs pci_set_power_state(pdev, PCI_D3hot); 961c5fd936eSLukas Wunner udelay(200); 9627bb6d442SBen Skeggs return 0; 9637bb6d442SBen Skeggs } 9647bb6d442SBen Skeggs 9657bb6d442SBen Skeggs int 9667bb6d442SBen Skeggs nouveau_pmops_resume(struct device *dev) 9672d8b9ccbSDave Airlie { 9682d8b9ccbSDave Airlie struct pci_dev *pdev = to_pci_dev(dev); 9692d8b9ccbSDave Airlie struct drm_device *drm_dev = pci_get_drvdata(pdev); 9702d8b9ccbSDave Airlie int ret; 9712d8b9ccbSDave Airlie 9725addcf0aSDave Airlie if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF || 9735addcf0aSDave Airlie drm_dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF) 9742d8b9ccbSDave Airlie return 0; 9752d8b9ccbSDave Airlie 9762d8b9ccbSDave Airlie pci_set_power_state(pdev, PCI_D0); 9772d8b9ccbSDave Airlie pci_restore_state(pdev); 9782d8b9ccbSDave Airlie ret = pci_enable_device(pdev); 9792d8b9ccbSDave Airlie if (ret) 9802d8b9ccbSDave Airlie return ret; 9812d8b9ccbSDave Airlie pci_set_master(pdev); 9822d8b9ccbSDave Airlie 9830b2fe659SHans de Goede ret = nouveau_do_resume(drm_dev, false); 9840b2fe659SHans de Goede 9850b2fe659SHans de Goede /* Monitors may have been connected / disconnected during suspend */ 986d297ce4bSLyude Paul nouveau_display_hpd_resume(drm_dev); 9870b2fe659SHans de Goede 9880b2fe659SHans de Goede return ret; 9892d8b9ccbSDave Airlie } 9902d8b9ccbSDave Airlie 9917bb6d442SBen Skeggs static int 9927bb6d442SBen Skeggs nouveau_pmops_freeze(struct device *dev) 9932d8b9ccbSDave Airlie { 9942d8b9ccbSDave Airlie struct pci_dev *pdev = to_pci_dev(dev); 9952d8b9ccbSDave Airlie struct drm_device *drm_dev = pci_get_drvdata(pdev); 9966fbb702eSBen Skeggs return nouveau_do_suspend(drm_dev, false); 9972d8b9ccbSDave Airlie } 9982d8b9ccbSDave Airlie 9997bb6d442SBen Skeggs static int 10007bb6d442SBen Skeggs nouveau_pmops_thaw(struct device *dev) 10012d8b9ccbSDave Airlie { 10022d8b9ccbSDave Airlie struct pci_dev *pdev = to_pci_dev(dev); 10032d8b9ccbSDave Airlie struct drm_device *drm_dev = pci_get_drvdata(pdev); 10046fbb702eSBen Skeggs return nouveau_do_resume(drm_dev, false); 10052d8b9ccbSDave Airlie } 10062d8b9ccbSDave Airlie 1007321f5c5fSBen Skeggs bool 10085499473cSArnd Bergmann nouveau_pmops_runtime(void) 1009321f5c5fSBen Skeggs { 1010321f5c5fSBen Skeggs if (nouveau_runtime_pm == -1) 1011321f5c5fSBen Skeggs return nouveau_is_optimus() || nouveau_is_v1_dsm(); 1012321f5c5fSBen Skeggs return nouveau_runtime_pm == 1; 1013321f5c5fSBen Skeggs } 1014321f5c5fSBen Skeggs 10157bb6d442SBen Skeggs static int 10167bb6d442SBen Skeggs nouveau_pmops_runtime_suspend(struct device *dev) 10177bb6d442SBen Skeggs { 10187bb6d442SBen Skeggs struct pci_dev *pdev = to_pci_dev(dev); 10197bb6d442SBen Skeggs struct drm_device *drm_dev = pci_get_drvdata(pdev); 10207bb6d442SBen Skeggs int ret; 10217bb6d442SBen Skeggs 1022321f5c5fSBen Skeggs if (!nouveau_pmops_runtime()) { 10237bb6d442SBen Skeggs pm_runtime_forbid(dev); 10247bb6d442SBen Skeggs return -EBUSY; 10257bb6d442SBen Skeggs } 10267bb6d442SBen Skeggs 10277bb6d442SBen Skeggs nouveau_switcheroo_optimus_dsm(); 10287bb6d442SBen Skeggs ret = nouveau_do_suspend(drm_dev, true); 10297bb6d442SBen Skeggs pci_save_state(pdev); 10307bb6d442SBen Skeggs pci_disable_device(pdev); 10318c863944SDave Airlie pci_ignore_hotplug(pdev); 10327bb6d442SBen Skeggs pci_set_power_state(pdev, PCI_D3cold); 10337bb6d442SBen Skeggs drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF; 10347bb6d442SBen Skeggs return ret; 10357bb6d442SBen Skeggs } 10367bb6d442SBen Skeggs 10377bb6d442SBen Skeggs static int 10387bb6d442SBen Skeggs nouveau_pmops_runtime_resume(struct device *dev) 10397bb6d442SBen Skeggs { 10407bb6d442SBen Skeggs struct pci_dev *pdev = to_pci_dev(dev); 10417bb6d442SBen Skeggs struct drm_device *drm_dev = pci_get_drvdata(pdev); 104230df16b9STobias Klausmann struct nouveau_drm *drm = nouveau_drm(drm_dev); 10431167c6bcSBen Skeggs struct nvif_device *device = &nouveau_drm(drm_dev)->client.device; 10447bb6d442SBen Skeggs int ret; 10457bb6d442SBen Skeggs 1046321f5c5fSBen Skeggs if (!nouveau_pmops_runtime()) { 1047321f5c5fSBen Skeggs pm_runtime_forbid(dev); 1048321f5c5fSBen Skeggs return -EBUSY; 1049321f5c5fSBen Skeggs } 10507bb6d442SBen Skeggs 10517bb6d442SBen Skeggs pci_set_power_state(pdev, PCI_D0); 10527bb6d442SBen Skeggs pci_restore_state(pdev); 10537bb6d442SBen Skeggs ret = pci_enable_device(pdev); 10547bb6d442SBen Skeggs if (ret) 10557bb6d442SBen Skeggs return ret; 10567bb6d442SBen Skeggs pci_set_master(pdev); 10577bb6d442SBen Skeggs 10587bb6d442SBen Skeggs ret = nouveau_do_resume(drm_dev, true); 105930df16b9STobias Klausmann if (ret) { 106030df16b9STobias Klausmann NV_ERROR(drm, "resume failed with: %d\n", ret); 106130df16b9STobias Klausmann return ret; 106230df16b9STobias Klausmann } 1063cae9ff03SLyude Paul 10647bb6d442SBen Skeggs /* do magic */ 1065a01ca78cSBen Skeggs nvif_mask(&device->object, 0x088488, (1 << 25), (1 << 25)); 10667bb6d442SBen Skeggs drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; 10670b2fe659SHans de Goede 10680b2fe659SHans de Goede /* Monitors may have been connected / disconnected during suspend */ 1069d297ce4bSLyude Paul nouveau_display_hpd_resume(drm_dev); 10700b2fe659SHans de Goede 10717bb6d442SBen Skeggs return ret; 10727bb6d442SBen Skeggs } 10737bb6d442SBen Skeggs 10747bb6d442SBen Skeggs static int 10757bb6d442SBen Skeggs nouveau_pmops_runtime_idle(struct device *dev) 10767bb6d442SBen Skeggs { 1077321f5c5fSBen Skeggs if (!nouveau_pmops_runtime()) { 10787bb6d442SBen Skeggs pm_runtime_forbid(dev); 10797bb6d442SBen Skeggs return -EBUSY; 10807bb6d442SBen Skeggs } 10817bb6d442SBen Skeggs 10827bb6d442SBen Skeggs pm_runtime_mark_last_busy(dev); 10837bb6d442SBen Skeggs pm_runtime_autosuspend(dev); 10847bb6d442SBen Skeggs /* we don't want the main rpm_idle to call suspend - we want to autosuspend */ 10857bb6d442SBen Skeggs return 1; 10867bb6d442SBen Skeggs } 10872d8b9ccbSDave Airlie 10885b8a43aeSMarcin Slusarz static int 1089ebb945a9SBen Skeggs nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) 1090ebb945a9SBen Skeggs { 1091ebb945a9SBen Skeggs struct nouveau_drm *drm = nouveau_drm(dev); 1092ebb945a9SBen Skeggs struct nouveau_cli *cli; 1093a2896cedSMarcin Slusarz char name[32], tmpname[TASK_COMM_LEN]; 1094ebb945a9SBen Skeggs int ret; 1095ebb945a9SBen Skeggs 10965addcf0aSDave Airlie /* need to bring up power immediately if opening device */ 10975addcf0aSDave Airlie ret = pm_runtime_get_sync(dev->dev); 1098659fb5f1SAditya Pakki if (ret < 0 && ret != -EACCES) { 1099659fb5f1SAditya Pakki pm_runtime_put_autosuspend(dev->dev); 11005addcf0aSDave Airlie return ret; 1101659fb5f1SAditya Pakki } 11025addcf0aSDave Airlie 1103a2896cedSMarcin Slusarz get_task_comm(tmpname, current); 1104a2896cedSMarcin Slusarz snprintf(name, sizeof(name), "%s[%d]", tmpname, pid_nr(fpriv->pid)); 1105fa6df8c1SBen Skeggs 1106922a8c82SLyude Paul if (!(cli = kzalloc(sizeof(*cli), GFP_KERNEL))) { 1107922a8c82SLyude Paul ret = -ENOMEM; 1108922a8c82SLyude Paul goto done; 1109922a8c82SLyude Paul } 1110420b9469SAlexandre Courbot 111120d8a88eSBen Skeggs ret = nouveau_cli_init(drm, name, cli); 1112ebb945a9SBen Skeggs if (ret) 111320d8a88eSBen Skeggs goto done; 1114ebb945a9SBen Skeggs 1115ebb945a9SBen Skeggs fpriv->driver_priv = cli; 1116ebb945a9SBen Skeggs 1117abae9164SJeremy Cline mutex_lock(&drm->clients_lock); 1118ebb945a9SBen Skeggs list_add(&cli->head, &drm->clients); 1119abae9164SJeremy Cline mutex_unlock(&drm->clients_lock); 11205addcf0aSDave Airlie 112120d8a88eSBen Skeggs done: 112220d8a88eSBen Skeggs if (ret && cli) { 112320d8a88eSBen Skeggs nouveau_cli_fini(cli); 112420d8a88eSBen Skeggs kfree(cli); 112520d8a88eSBen Skeggs } 112620d8a88eSBen Skeggs 11275addcf0aSDave Airlie pm_runtime_mark_last_busy(dev->dev); 11285addcf0aSDave Airlie pm_runtime_put_autosuspend(dev->dev); 11295addcf0aSDave Airlie return ret; 1130ebb945a9SBen Skeggs } 1131ebb945a9SBen Skeggs 11325b8a43aeSMarcin Slusarz static void 1133f0e73ff3SDaniel Vetter nouveau_drm_postclose(struct drm_device *dev, struct drm_file *fpriv) 1134ebb945a9SBen Skeggs { 1135ebb945a9SBen Skeggs struct nouveau_cli *cli = nouveau_cli(fpriv); 1136ebb945a9SBen Skeggs struct nouveau_drm *drm = nouveau_drm(dev); 1137f55aaf63SJeremy Cline int dev_index; 1138f55aaf63SJeremy Cline 1139f55aaf63SJeremy Cline /* 1140f55aaf63SJeremy Cline * The device is gone, and as it currently stands all clients are 1141f55aaf63SJeremy Cline * cleaned up in the removal codepath. In the future this may change 1142f55aaf63SJeremy Cline * so that we can support hot-unplugging, but for now we immediately 1143f55aaf63SJeremy Cline * return to avoid a double-free situation. 1144f55aaf63SJeremy Cline */ 1145f55aaf63SJeremy Cline if (!drm_dev_enter(dev, &dev_index)) 1146f55aaf63SJeremy Cline return; 1147ebb945a9SBen Skeggs 11485addcf0aSDave Airlie pm_runtime_get_sync(dev->dev); 11495addcf0aSDave Airlie 1150ac8c7930SKamil Dudka mutex_lock(&cli->mutex); 1151ebb945a9SBen Skeggs if (cli->abi16) 1152ebb945a9SBen Skeggs nouveau_abi16_fini(cli->abi16); 1153ac8c7930SKamil Dudka mutex_unlock(&cli->mutex); 1154ebb945a9SBen Skeggs 1155abae9164SJeremy Cline mutex_lock(&drm->clients_lock); 1156ebb945a9SBen Skeggs list_del(&cli->head); 1157abae9164SJeremy Cline mutex_unlock(&drm->clients_lock); 11585addcf0aSDave Airlie 115920d8a88eSBen Skeggs nouveau_cli_fini(cli); 116020d8a88eSBen Skeggs kfree(cli); 11615addcf0aSDave Airlie pm_runtime_mark_last_busy(dev->dev); 11625addcf0aSDave Airlie pm_runtime_put_autosuspend(dev->dev); 1163f55aaf63SJeremy Cline drm_dev_exit(dev_index); 1164ebb945a9SBen Skeggs } 1165ebb945a9SBen Skeggs 1166baa70943SRob Clark static const struct drm_ioctl_desc 116777145f1cSBen Skeggs nouveau_ioctls[] = { 1168a305f6c5SEmil Velikov DRM_IOCTL_DEF_DRV(NOUVEAU_GETPARAM, nouveau_abi16_ioctl_getparam, DRM_RENDER_ALLOW), 116994533c41SEmil Velikov DRM_IOCTL_DEF_DRV(NOUVEAU_SETPARAM, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 1170a305f6c5SEmil Velikov DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_ALLOC, nouveau_abi16_ioctl_channel_alloc, DRM_RENDER_ALLOW), 1171a305f6c5SEmil Velikov DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_FREE, nouveau_abi16_ioctl_channel_free, DRM_RENDER_ALLOW), 1172a305f6c5SEmil Velikov DRM_IOCTL_DEF_DRV(NOUVEAU_GROBJ_ALLOC, nouveau_abi16_ioctl_grobj_alloc, DRM_RENDER_ALLOW), 1173a305f6c5SEmil Velikov DRM_IOCTL_DEF_DRV(NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_abi16_ioctl_notifierobj_alloc, DRM_RENDER_ALLOW), 1174a305f6c5SEmil Velikov DRM_IOCTL_DEF_DRV(NOUVEAU_GPUOBJ_FREE, nouveau_abi16_ioctl_gpuobj_free, DRM_RENDER_ALLOW), 1175a305f6c5SEmil Velikov DRM_IOCTL_DEF_DRV(NOUVEAU_SVM_INIT, nouveau_svmm_init, DRM_RENDER_ALLOW), 1176a305f6c5SEmil Velikov DRM_IOCTL_DEF_DRV(NOUVEAU_SVM_BIND, nouveau_svmm_bind, DRM_RENDER_ALLOW), 1177a305f6c5SEmil Velikov DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_RENDER_ALLOW), 1178a305f6c5SEmil Velikov DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_RENDER_ALLOW), 1179a305f6c5SEmil Velikov DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_RENDER_ALLOW), 1180a305f6c5SEmil Velikov DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_RENDER_ALLOW), 1181a305f6c5SEmil Velikov DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_RENDER_ALLOW), 118277145f1cSBen Skeggs }; 118377145f1cSBen Skeggs 118427111a23SBen Skeggs long 118527111a23SBen Skeggs nouveau_drm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 11865addcf0aSDave Airlie { 118727111a23SBen Skeggs struct drm_file *filp = file->private_data; 118827111a23SBen Skeggs struct drm_device *dev = filp->minor->dev; 11895addcf0aSDave Airlie long ret; 11905addcf0aSDave Airlie 11915addcf0aSDave Airlie ret = pm_runtime_get_sync(dev->dev); 1192659fb5f1SAditya Pakki if (ret < 0 && ret != -EACCES) { 1193659fb5f1SAditya Pakki pm_runtime_put_autosuspend(dev->dev); 11945addcf0aSDave Airlie return ret; 1195659fb5f1SAditya Pakki } 11965addcf0aSDave Airlie 119727111a23SBen Skeggs switch (_IOC_NR(cmd) - DRM_COMMAND_BASE) { 119827111a23SBen Skeggs case DRM_NOUVEAU_NVIF: 119927111a23SBen Skeggs ret = usif_ioctl(filp, (void __user *)arg, _IOC_SIZE(cmd)); 120027111a23SBen Skeggs break; 120127111a23SBen Skeggs default: 120227111a23SBen Skeggs ret = drm_ioctl(file, cmd, arg); 120327111a23SBen Skeggs break; 120427111a23SBen Skeggs } 12055addcf0aSDave Airlie 12065addcf0aSDave Airlie pm_runtime_mark_last_busy(dev->dev); 12075addcf0aSDave Airlie pm_runtime_put_autosuspend(dev->dev); 12085addcf0aSDave Airlie return ret; 12095addcf0aSDave Airlie } 121027111a23SBen Skeggs 121177145f1cSBen Skeggs static const struct file_operations 121277145f1cSBen Skeggs nouveau_driver_fops = { 121377145f1cSBen Skeggs .owner = THIS_MODULE, 121477145f1cSBen Skeggs .open = drm_open, 121577145f1cSBen Skeggs .release = drm_release, 12165addcf0aSDave Airlie .unlocked_ioctl = nouveau_drm_ioctl, 1217265ec0ddSThomas Zimmermann .mmap = drm_gem_mmap, 121877145f1cSBen Skeggs .poll = drm_poll, 121977145f1cSBen Skeggs .read = drm_read, 122077145f1cSBen Skeggs #if defined(CONFIG_COMPAT) 122177145f1cSBen Skeggs .compat_ioctl = nouveau_compat_ioctl, 122277145f1cSBen Skeggs #endif 122377145f1cSBen Skeggs .llseek = noop_llseek, 122477145f1cSBen Skeggs }; 122577145f1cSBen Skeggs 122677145f1cSBen Skeggs static struct drm_driver 1227915b4d11SDavid Herrmann driver_stub = { 1228cf8698dfSThomas Zimmermann .driver_features = DRIVER_GEM | 1229cf8698dfSThomas Zimmermann DRIVER_MODESET | 1230cf8698dfSThomas Zimmermann DRIVER_RENDER, 123177145f1cSBen Skeggs .open = nouveau_drm_open, 123277145f1cSBen Skeggs .postclose = nouveau_drm_postclose, 123377145f1cSBen Skeggs .lastclose = nouveau_vga_lastclose, 123477145f1cSBen Skeggs 123533b903e8SMarcin Slusarz #if defined(CONFIG_DEBUG_FS) 123656c101afSKarol Herbst .debugfs_init = nouveau_drm_debugfs_init, 123733b903e8SMarcin Slusarz #endif 123833b903e8SMarcin Slusarz 123977145f1cSBen Skeggs .ioctls = nouveau_ioctls, 1240baa70943SRob Clark .num_ioctls = ARRAY_SIZE(nouveau_ioctls), 124177145f1cSBen Skeggs .fops = &nouveau_driver_fops, 124277145f1cSBen Skeggs 124377145f1cSBen Skeggs .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 124477145f1cSBen Skeggs .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 1245ab9ccb96SAaron Plattner .gem_prime_import_sg_table = nouveau_gem_prime_import_sg_table, 1246265ec0ddSThomas Zimmermann .gem_prime_mmap = drm_gem_prime_mmap, 124777145f1cSBen Skeggs 124877145f1cSBen Skeggs .dumb_create = nouveau_display_dumb_create, 12494c398f50SThomas Zimmermann .dumb_map_offset = drm_gem_ttm_dumb_map_offset, 125077145f1cSBen Skeggs 125177145f1cSBen Skeggs .name = DRIVER_NAME, 125277145f1cSBen Skeggs .desc = DRIVER_DESC, 125377145f1cSBen Skeggs #ifdef GIT_REVISION 125477145f1cSBen Skeggs .date = GIT_REVISION, 125577145f1cSBen Skeggs #else 125677145f1cSBen Skeggs .date = DRIVER_DATE, 125777145f1cSBen Skeggs #endif 125877145f1cSBen Skeggs .major = DRIVER_MAJOR, 125977145f1cSBen Skeggs .minor = DRIVER_MINOR, 126077145f1cSBen Skeggs .patchlevel = DRIVER_PATCHLEVEL, 126177145f1cSBen Skeggs }; 126277145f1cSBen Skeggs 126394580299SBen Skeggs static struct pci_device_id 126494580299SBen Skeggs nouveau_drm_pci_table[] = { 126594580299SBen Skeggs { 126694580299SBen Skeggs PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), 126794580299SBen Skeggs .class = PCI_BASE_CLASS_DISPLAY << 16, 126894580299SBen Skeggs .class_mask = 0xff << 16, 126994580299SBen Skeggs }, 127094580299SBen Skeggs { 127194580299SBen Skeggs PCI_DEVICE(PCI_VENDOR_ID_NVIDIA_SGS, PCI_ANY_ID), 127294580299SBen Skeggs .class = PCI_BASE_CLASS_DISPLAY << 16, 127394580299SBen Skeggs .class_mask = 0xff << 16, 127494580299SBen Skeggs }, 127594580299SBen Skeggs {} 127694580299SBen Skeggs }; 127794580299SBen Skeggs 1278703fa264SPierre Moreau static void nouveau_display_options(void) 1279703fa264SPierre Moreau { 1280703fa264SPierre Moreau DRM_DEBUG_DRIVER("Loading Nouveau with parameters:\n"); 1281703fa264SPierre Moreau 1282703fa264SPierre Moreau DRM_DEBUG_DRIVER("... tv_disable : %d\n", nouveau_tv_disable); 1283703fa264SPierre Moreau DRM_DEBUG_DRIVER("... ignorelid : %d\n", nouveau_ignorelid); 1284703fa264SPierre Moreau DRM_DEBUG_DRIVER("... duallink : %d\n", nouveau_duallink); 1285703fa264SPierre Moreau DRM_DEBUG_DRIVER("... config : %s\n", nouveau_config); 1286703fa264SPierre Moreau DRM_DEBUG_DRIVER("... debug : %s\n", nouveau_debug); 1287703fa264SPierre Moreau DRM_DEBUG_DRIVER("... noaccel : %d\n", nouveau_noaccel); 1288703fa264SPierre Moreau DRM_DEBUG_DRIVER("... modeset : %d\n", nouveau_modeset); 1289703fa264SPierre Moreau DRM_DEBUG_DRIVER("... runpm : %d\n", nouveau_runtime_pm); 1290703fa264SPierre Moreau DRM_DEBUG_DRIVER("... vram_pushbuf : %d\n", nouveau_vram_pushbuf); 1291f3a8b664SBen Skeggs DRM_DEBUG_DRIVER("... hdmimhz : %d\n", nouveau_hdmimhz); 1292703fa264SPierre Moreau } 1293703fa264SPierre Moreau 12942d8b9ccbSDave Airlie static const struct dev_pm_ops nouveau_pm_ops = { 12952d8b9ccbSDave Airlie .suspend = nouveau_pmops_suspend, 12962d8b9ccbSDave Airlie .resume = nouveau_pmops_resume, 12972d8b9ccbSDave Airlie .freeze = nouveau_pmops_freeze, 12982d8b9ccbSDave Airlie .thaw = nouveau_pmops_thaw, 12992d8b9ccbSDave Airlie .poweroff = nouveau_pmops_freeze, 13002d8b9ccbSDave Airlie .restore = nouveau_pmops_resume, 13015addcf0aSDave Airlie .runtime_suspend = nouveau_pmops_runtime_suspend, 13025addcf0aSDave Airlie .runtime_resume = nouveau_pmops_runtime_resume, 13035addcf0aSDave Airlie .runtime_idle = nouveau_pmops_runtime_idle, 13042d8b9ccbSDave Airlie }; 13052d8b9ccbSDave Airlie 130694580299SBen Skeggs static struct pci_driver 130794580299SBen Skeggs nouveau_drm_pci_driver = { 130894580299SBen Skeggs .name = "nouveau", 130994580299SBen Skeggs .id_table = nouveau_drm_pci_table, 131094580299SBen Skeggs .probe = nouveau_drm_probe, 131194580299SBen Skeggs .remove = nouveau_drm_remove, 13122d8b9ccbSDave Airlie .driver.pm = &nouveau_pm_ops, 131394580299SBen Skeggs }; 131494580299SBen Skeggs 13158ba9ff11SAlexandre Courbot struct drm_device * 1316e396ecd1SAlexandre Courbot nouveau_platform_device_create(const struct nvkm_device_tegra_func *func, 1317e396ecd1SAlexandre Courbot struct platform_device *pdev, 131847b2505eSBen Skeggs struct nvkm_device **pdevice) 1319420b9469SAlexandre Courbot { 13208ba9ff11SAlexandre Courbot struct drm_device *drm; 13218ba9ff11SAlexandre Courbot int err; 1322420b9469SAlexandre Courbot 1323e396ecd1SAlexandre Courbot err = nvkm_device_tegra_new(func, pdev, nouveau_config, nouveau_debug, 13247974dd1bSBen Skeggs true, true, ~0ULL, pdevice); 13258ba9ff11SAlexandre Courbot if (err) 1326e781dc8fSBen Skeggs goto err_free; 1327420b9469SAlexandre Courbot 1328915b4d11SDavid Herrmann drm = drm_dev_alloc(&driver_platform, &pdev->dev); 13290f288605STom Gundersen if (IS_ERR(drm)) { 13300f288605STom Gundersen err = PTR_ERR(drm); 13318ba9ff11SAlexandre Courbot goto err_free; 1332420b9469SAlexandre Courbot } 1333420b9469SAlexandre Courbot 13344ac0a807SThierry Reding err = nouveau_drm_device_init(drm); 13354ac0a807SThierry Reding if (err) 13364ac0a807SThierry Reding goto err_put; 13374ac0a807SThierry Reding 13388ba9ff11SAlexandre Courbot platform_set_drvdata(pdev, drm); 13398ba9ff11SAlexandre Courbot 13408ba9ff11SAlexandre Courbot return drm; 13418ba9ff11SAlexandre Courbot 13424ac0a807SThierry Reding err_put: 13434ac0a807SThierry Reding drm_dev_put(drm); 13448ba9ff11SAlexandre Courbot err_free: 1345e781dc8fSBen Skeggs nvkm_device_del(pdevice); 13468ba9ff11SAlexandre Courbot 13478ba9ff11SAlexandre Courbot return ERR_PTR(err); 1348420b9469SAlexandre Courbot } 1349420b9469SAlexandre Courbot 135094580299SBen Skeggs static int __init 135194580299SBen Skeggs nouveau_drm_init(void) 135294580299SBen Skeggs { 1353915b4d11SDavid Herrmann driver_pci = driver_stub; 1354915b4d11SDavid Herrmann driver_platform = driver_stub; 1355915b4d11SDavid Herrmann 1356703fa264SPierre Moreau nouveau_display_options(); 1357703fa264SPierre Moreau 135877145f1cSBen Skeggs if (nouveau_modeset == -1) { 13596a2d2ddfSJavier Martinez Canillas if (drm_firmware_drivers_only()) 136077145f1cSBen Skeggs nouveau_modeset = 0; 136177145f1cSBen Skeggs } 136277145f1cSBen Skeggs 136377145f1cSBen Skeggs if (!nouveau_modeset) 136477145f1cSBen Skeggs return 0; 136577145f1cSBen Skeggs 1366055a65d5SAlexandre Courbot #ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER 1367055a65d5SAlexandre Courbot platform_driver_register(&nouveau_platform_driver); 1368055a65d5SAlexandre Courbot #endif 1369055a65d5SAlexandre Courbot 137077145f1cSBen Skeggs nouveau_register_dsm_handler(); 1371db1a0ae2SPierre Moreau nouveau_backlight_ctor(); 137210631d72SDaniel Vetter 137310631d72SDaniel Vetter #ifdef CONFIG_PCI 137410631d72SDaniel Vetter return pci_register_driver(&nouveau_drm_pci_driver); 137510631d72SDaniel Vetter #else 137610631d72SDaniel Vetter return 0; 137710631d72SDaniel Vetter #endif 137894580299SBen Skeggs } 137994580299SBen Skeggs 138094580299SBen Skeggs static void __exit 138194580299SBen Skeggs nouveau_drm_exit(void) 138294580299SBen Skeggs { 138377145f1cSBen Skeggs if (!nouveau_modeset) 138477145f1cSBen Skeggs return; 138577145f1cSBen Skeggs 138610631d72SDaniel Vetter #ifdef CONFIG_PCI 138710631d72SDaniel Vetter pci_unregister_driver(&nouveau_drm_pci_driver); 138810631d72SDaniel Vetter #endif 1389db1a0ae2SPierre Moreau nouveau_backlight_dtor(); 139077145f1cSBen Skeggs nouveau_unregister_dsm_handler(); 1391055a65d5SAlexandre Courbot 1392055a65d5SAlexandre Courbot #ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER 1393055a65d5SAlexandre Courbot platform_driver_unregister(&nouveau_platform_driver); 1394055a65d5SAlexandre Courbot #endif 1395c7d8b782SJason Gunthorpe if (IS_ENABLED(CONFIG_DRM_NOUVEAU_SVM)) 1396c7d8b782SJason Gunthorpe mmu_notifier_synchronize(); 139794580299SBen Skeggs } 139894580299SBen Skeggs 139994580299SBen Skeggs module_init(nouveau_drm_init); 140094580299SBen Skeggs module_exit(nouveau_drm_exit); 140194580299SBen Skeggs 140294580299SBen Skeggs MODULE_DEVICE_TABLE(pci, nouveau_drm_pci_table); 140377145f1cSBen Skeggs MODULE_AUTHOR(DRIVER_AUTHOR); 140477145f1cSBen Skeggs MODULE_DESCRIPTION(DRIVER_DESC); 140594580299SBen Skeggs MODULE_LICENSE("GPL and additional rights"); 1406