From 9458029940ffc64bca0c5a30ea626c377205842e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 6 Jul 2012 12:14:00 +1000 Subject: drm/nouveau: implement module init functions in nouveau_drm.c These currently just call the existing ones in nouveau_drv.c, but will be extended in upcoming commits. This needed to be separated from the current code as there will be some header clashes until things are ported. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drm.c | 285 ++++++++++++++++++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 drivers/gpu/drm/nouveau/nouveau_drm.c (limited to 'drivers/gpu/drm/nouveau/nouveau_drm.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c new file mode 100644 index 000000000000..c72d42636c89 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -0,0 +1,285 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include +#include + +#include +#include +#include + +#include + +#include "nouveau_drm.h" + +int __devinit nouveau_pci_probe(struct pci_dev *, const struct pci_device_id *); +void nouveau_pci_remove(struct pci_dev *); +int nouveau_pci_suspend(struct pci_dev *, pm_message_t); +int nouveau_pci_resume(struct pci_dev *); +int __init nouveau_init(struct pci_driver *); +void __exit nouveau_exit(struct pci_driver *); + +int nouveau_load(struct drm_device *, unsigned long); +int nouveau_unload(struct drm_device *); +void *nouveau_newpriv(struct drm_device *); + +MODULE_PARM_DESC(config, "option string to pass to driver core"); +static char *nouveau_config; +module_param_named(config, nouveau_config, charp, 0400); + +MODULE_PARM_DESC(debug, "debug string to pass to driver core"); +static char *nouveau_debug; +module_param_named(debug, nouveau_debug, charp, 0400); + +static u64 +nouveau_name(struct pci_dev *pdev) +{ + u64 name = (u64)pci_domain_nr(pdev->bus) << 32; + name |= pdev->bus->number << 16; + name |= PCI_SLOT(pdev->devfn) << 8; + return name | PCI_FUNC(pdev->devfn); +} + +static int +nouveau_cli_create(struct pci_dev *pdev, u32 name, int size, void **pcli) +{ + struct nouveau_cli *cli; + int ret; + + ret = nouveau_client_create_(name, nouveau_name(pdev), nouveau_config, + nouveau_debug, size, pcli); + cli = *pcli; + if (ret) + return ret; + + mutex_init(&cli->mutex); + return 0; +} + +static void +nouveau_cli_destroy(struct nouveau_cli *cli) +{ + struct nouveau_object *client = nv_object(cli); + nouveau_client_fini(&cli->base, false); + atomic_set(&client->refcount, 1); + nouveau_object_ref(NULL, &client); +} + +static int __devinit +nouveau_drm_probe(struct pci_dev *pdev, const struct pci_device_id *pent) +{ + struct nouveau_device *device; + int ret; + + ret = nouveau_device_create(pdev, nouveau_name(pdev), pci_name(pdev), + nouveau_config, nouveau_debug, &device); + if (ret) + return ret; + + pci_set_master(pdev); + + ret = nouveau_pci_probe(pdev, pent); + if (ret) { + nouveau_device_destroy(&device); + return ret; + } + + return 0; +} + +int +nouveau_drm_load(struct drm_device *dev, unsigned long flags) +{ + struct pci_dev *pdev = dev->pdev; + struct nouveau_drm *drm; + int ret; + + ret = nouveau_cli_create(pdev, 0, sizeof(*drm), (void**)&drm); + dev->dev_private = drm; + if (ret) + return ret; + + INIT_LIST_HEAD(&drm->clients); + drm->dev = dev; + + ret = nouveau_object_new(nv_object(drm), NVDRM_CLIENT, NVDRM_DEVICE, + 0x0080, &(struct nv_device_class) { + .device = ~0, + .disable = 0, + .debug0 = 0, + }, sizeof(struct nv_device_class), + &drm->device); + if (ret) + goto fail_device; + + ret = nouveau_load(dev, flags); + if (ret) + goto fail_device; + + return 0; + +fail_device: + nouveau_cli_destroy(&drm->client); + return ret; +} + +int +nouveau_drm_unload(struct drm_device *dev) +{ + struct nouveau_drm *drm = nouveau_newpriv(dev); + struct pci_dev *pdev = dev->pdev; + int ret; + + ret = nouveau_unload(dev); + if (ret) + return ret; + + pci_set_drvdata(pdev, drm->client.base.device); + nouveau_cli_destroy(&drm->client); + return 0; +} + +static void +nouveau_drm_remove(struct pci_dev *pdev) +{ + struct nouveau_device *device; + nouveau_pci_remove(pdev); + device = pci_get_drvdata(pdev); + nouveau_device_destroy(&device); +} + +int +nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + struct nouveau_drm *drm = nouveau_newpriv(dev); + struct nouveau_cli *cli; + int ret; + + if (dev->switch_power_state == DRM_SWITCH_POWER_OFF || + pm_state.event == PM_EVENT_PRETHAW) + return 0; + + ret = nouveau_pci_suspend(pdev, pm_state); + if (ret) + return ret; + + list_for_each_entry(cli, &drm->clients, head) { + ret = nouveau_client_fini(&cli->base, true); + if (ret) + goto fail_client; + } + + ret = nouveau_client_fini(&drm->client.base, true); + if (ret) + goto fail_client; + + pci_save_state(pdev); + if (pm_state.event == PM_EVENT_SUSPEND) { + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + } + + return 0; + +fail_client: + list_for_each_entry_continue_reverse(cli, &drm->clients, head) { + nouveau_client_init(&cli->base); + } + + nouveau_pci_resume(pdev); + return ret; +} + +int +nouveau_drm_resume(struct pci_dev *pdev) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + struct nouveau_drm *drm = nouveau_newpriv(dev); + struct nouveau_cli *cli; + int ret; + + if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) + return 0; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + ret = pci_enable_device(pdev); + if (ret) + return ret; + pci_set_master(pdev); + + nouveau_client_init(&drm->client.base); + + list_for_each_entry(cli, &drm->clients, head) { + nouveau_client_init(&cli->base); + } + + return nouveau_pci_resume(pdev); +} + +static struct pci_device_id +nouveau_drm_pci_table[] = { + { + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), + .class = PCI_BASE_CLASS_DISPLAY << 16, + .class_mask = 0xff << 16, + }, + { + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA_SGS, PCI_ANY_ID), + .class = PCI_BASE_CLASS_DISPLAY << 16, + .class_mask = 0xff << 16, + }, + {} +}; + +static struct pci_driver +nouveau_drm_pci_driver = { + .name = "nouveau", + .id_table = nouveau_drm_pci_table, + .probe = nouveau_drm_probe, + .remove = nouveau_drm_remove, + .suspend = nouveau_drm_suspend, + .resume = nouveau_drm_resume, +}; + +static int __init +nouveau_drm_init(void) +{ + return nouveau_init(&nouveau_drm_pci_driver); +} + +static void __exit +nouveau_drm_exit(void) +{ + nouveau_exit(&nouveau_drm_pci_driver); +} + +module_init(nouveau_drm_init); +module_exit(nouveau_drm_exit); + +MODULE_DEVICE_TABLE(pci, nouveau_drm_pci_table); +MODULE_AUTHOR("Nouveau Project"); +MODULE_DESCRIPTION("nVidia Riva/TNT/GeForce/Quadro/Tesla"); +MODULE_LICENSE("GPL and additional rights"); -- cgit From cb75d97e9c77743ecfcc43375be135a55a4d9b25 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 11 Jul 2012 10:44:20 +1000 Subject: drm/nouveau: implement devinit subdev, and new init table parser v2: - make sure not to execute display scripts unless resuming Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drm.c | 36 +++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'drivers/gpu/drm/nouveau/nouveau_drm.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index c72d42636c89..3b4e65d5122b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -32,6 +32,7 @@ #include #include "nouveau_drm.h" +#include "nouveau_agp.h" int __devinit nouveau_pci_probe(struct pci_dev *, const struct pci_device_id *); void nouveau_pci_remove(struct pci_dev *); @@ -123,6 +124,30 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) INIT_LIST_HEAD(&drm->clients); drm->dev = dev; + /* make sure AGP controller is in a consistent state before we + * (possibly) execute vbios init tables (see nouveau_agp.h) + */ + if (drm_pci_device_is_agp(dev) && dev->agp) { + /* dummy device object, doesn't init anything, but allows + * agp code access to registers + */ + ret = nouveau_object_new(nv_object(drm), NVDRM_CLIENT, + NVDRM_DEVICE, 0x0080, + &(struct nv_device_class) { + .device = ~0, + .disable = + ~(NV_DEVICE_DISABLE_MMIO | + NV_DEVICE_DISABLE_IDENTIFY), + .debug0 = ~0, + }, sizeof(struct nv_device_class), + &drm->device); + if (ret) + return ret; + + nouveau_agp_reset(drm); + nouveau_object_del(nv_object(drm), NVDRM_CLIENT, NVDRM_DEVICE); + } + ret = nouveau_object_new(nv_object(drm), NVDRM_CLIENT, NVDRM_DEVICE, 0x0080, &(struct nv_device_class) { .device = ~0, @@ -133,6 +158,9 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) if (ret) goto fail_device; + /* initialise AGP */ + nouveau_agp_init(drm); + ret = nouveau_load(dev, flags); if (ret) goto fail_device; @@ -155,6 +183,8 @@ nouveau_drm_unload(struct drm_device *dev) if (ret) return ret; + nouveau_agp_fini(drm); + pci_set_drvdata(pdev, drm->client.base.device); nouveau_cli_destroy(&drm->client); return 0; @@ -195,6 +225,8 @@ nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state) if (ret) goto fail_client; + nouveau_agp_fini(drm); + pci_save_state(pdev); if (pm_state.event == PM_EVENT_SUSPEND) { pci_disable_device(pdev); @@ -230,12 +262,16 @@ nouveau_drm_resume(struct pci_dev *pdev) return ret; pci_set_master(pdev); + nouveau_agp_reset(drm); + nouveau_client_init(&drm->client.base); list_for_each_entry(cli, &drm->clients, head) { nouveau_client_init(&cli->base); } + nouveau_agp_init(drm); + return nouveau_pci_resume(pdev); } -- cgit From ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 20 Jul 2012 08:17:34 +1000 Subject: drm/nouveau: port all engines to new engine module format This is a HUGE commit, but it's not nearly as bad as it looks - any problems can be isolated to a particular chipset and engine combination. It was simply too difficult to port each one at a time, the compat layers are *already* ridiculous. Most of the changes here are simply to the glue, the process for each of the engine modules was to start with a standard skeleton and copy+paste the old code into the appropriate places, fixing up variable names etc as needed. v2: Marcin Slusarz - fix find/replace bug in license header v3: Ben Skeggs - bump indirect pushbuf size to 8KiB, 4KiB barely enough for userspace and left no space for kernel's requirements during GEM pushbuf submission. - fix duplicate assignments noticed by clang v4: Marcin Slusarz - add sparse annotations to nv04_fifo_pause/nv04_fifo_start - use ioread32_native/iowrite32_native for fifo control registers v5: Ben Skeggs - rebase on v3.6-rc4, modified to keep copy engine fix intact - nv10/fence: unmap fence bo before destroying - fixed fermi regression when using nvidia gr fuc - fixed typo in supported dma_mask checking Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drm.c | 211 ++++++++++++++++++++++++++++++++-- 1 file changed, 204 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nouveau_drm.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 3b4e65d5122b..92ecf50a39d3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -27,12 +27,20 @@ #include #include +#include #include #include +#include #include "nouveau_drm.h" +#include "nouveau_dma.h" #include "nouveau_agp.h" +#include "nouveau_abi16.h" +#include "nouveau_fbcon.h" +#include "nouveau_fence.h" + +#include "nouveau_ttm.h" int __devinit nouveau_pci_probe(struct pci_dev *, const struct pci_device_id *); void nouveau_pci_remove(struct pci_dev *); @@ -43,7 +51,6 @@ void __exit nouveau_exit(struct pci_driver *); int nouveau_load(struct drm_device *, unsigned long); int nouveau_unload(struct drm_device *); -void *nouveau_newpriv(struct drm_device *); MODULE_PARM_DESC(config, "option string to pass to driver core"); static char *nouveau_config; @@ -53,6 +60,10 @@ MODULE_PARM_DESC(debug, "debug string to pass to driver core"); static char *nouveau_debug; module_param_named(debug, nouveau_debug, charp, 0400); +MODULE_PARM_DESC(noaccel, "disable kernel/abi16 acceleration"); +static int nouveau_noaccel = 0; +module_param_named(noaccel, nouveau_noaccel, int, 0400); + static u64 nouveau_name(struct pci_dev *pdev) { @@ -82,17 +93,112 @@ static void nouveau_cli_destroy(struct nouveau_cli *cli) { struct nouveau_object *client = nv_object(cli); + nouveau_vm_ref(NULL, &cli->base.vm, NULL); nouveau_client_fini(&cli->base, false); atomic_set(&client->refcount, 1); nouveau_object_ref(NULL, &client); } +static void +nouveau_accel_fini(struct nouveau_drm *drm) +{ + nouveau_gpuobj_ref(NULL, &drm->notify); + nouveau_channel_del(&drm->channel); + if (drm->fence) + nouveau_fence(drm)->dtor(drm); +} + +static void +nouveau_accel_init(struct nouveau_drm *drm) +{ + struct nouveau_device *device = nv_device(drm->device); + struct nouveau_object *object; + int ret; + + if (nouveau_noaccel) + return; + + /* initialise synchronisation routines */ + if (device->card_type < NV_10) ret = nv04_fence_create(drm); + else if (device->chipset < 0x84) ret = nv10_fence_create(drm); + else if (device->card_type < NV_C0) ret = nv84_fence_create(drm); + else ret = nvc0_fence_create(drm); + if (ret) { + NV_ERROR(drm, "failed to initialise sync subsystem, %d\n", ret); + nouveau_accel_fini(drm); + return; + } + + ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE, NVDRM_CHAN, + NvDmaFB, NvDmaTT, &drm->channel); + if (ret) { + NV_ERROR(drm, "failed to create kernel channel, %d\n", ret); + nouveau_accel_fini(drm); + return; + } + + if (device->card_type < NV_C0) { + ret = nouveau_gpuobj_new(drm->device, NULL, 32, 0, 0, + &drm->notify); + if (ret) { + NV_ERROR(drm, "failed to allocate notifier, %d\n", ret); + nouveau_accel_fini(drm); + return; + } + + ret = nouveau_object_new(nv_object(drm), + drm->channel->handle, NvNotify0, + 0x003d, &(struct nv_dma_class) { + .flags = NV_DMA_TARGET_VRAM | + NV_DMA_ACCESS_RDWR, + .start = drm->notify->addr, + .limit = drm->notify->addr + 31 + }, sizeof(struct nv_dma_class), + &object); + if (ret) { + nouveau_accel_fini(drm); + return; + } + } + + + nouveau_bo_move_init(drm->channel); +} + static int __devinit nouveau_drm_probe(struct pci_dev *pdev, const struct pci_device_id *pent) { struct nouveau_device *device; + struct apertures_struct *aper; + bool boot = false; int ret; + /* remove conflicting drivers (vesafb, efifb etc) */ + aper = alloc_apertures(3); + if (!aper) + return -ENOMEM; + + aper->ranges[0].base = pci_resource_start(pdev, 1); + aper->ranges[0].size = pci_resource_len(pdev, 1); + aper->count = 1; + + if (pci_resource_len(pdev, 2)) { + aper->ranges[aper->count].base = pci_resource_start(pdev, 2); + aper->ranges[aper->count].size = pci_resource_len(pdev, 2); + aper->count++; + } + + if (pci_resource_len(pdev, 3)) { + aper->ranges[aper->count].base = pci_resource_start(pdev, 3); + aper->ranges[aper->count].size = pci_resource_len(pdev, 3); + aper->count++; + } + +#ifdef CONFIG_X86 + boot = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; +#endif + remove_conflicting_framebuffers(aper, "nouveaufb", boot); + ret = nouveau_device_create(pdev, nouveau_name(pdev), pci_name(pdev), nouveau_config, nouveau_debug, &device); if (ret) @@ -102,7 +208,7 @@ nouveau_drm_probe(struct pci_dev *pdev, const struct pci_device_id *pent) ret = nouveau_pci_probe(pdev, pent); if (ret) { - nouveau_device_destroy(&device); + nouveau_object_ref(NULL, (struct nouveau_object **)&device); return ret; } @@ -113,6 +219,7 @@ int nouveau_drm_load(struct drm_device *dev, unsigned long flags) { struct pci_dev *pdev = dev->pdev; + struct nouveau_device *device; struct nouveau_drm *drm; int ret; @@ -122,6 +229,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) return ret; INIT_LIST_HEAD(&drm->clients); + spin_lock_init(&drm->tile.lock); drm->dev = dev; /* make sure AGP controller is in a consistent state before we @@ -142,7 +250,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) }, sizeof(struct nv_device_class), &drm->device); if (ret) - return ret; + goto fail_device; nouveau_agp_reset(drm); nouveau_object_del(nv_object(drm), NVDRM_CLIENT, NVDRM_DEVICE); @@ -158,15 +266,32 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) if (ret) goto fail_device; + device = nv_device(drm->device); + /* initialise AGP */ nouveau_agp_init(drm); - ret = nouveau_load(dev, flags); + if (device->card_type >= NV_50) { + ret = nouveau_vm_new(nv_device(drm->device), 0, (1ULL << 40), + 0x1000, &drm->client.base.vm); + if (ret) + goto fail_device; + } + + ret = nouveau_ttm_init(drm); if (ret) goto fail_device; + ret = nouveau_load(dev, flags); + if (ret) + goto fail_load; + + nouveau_accel_init(drm); + nouveau_fbcon_init(dev); return 0; +fail_load: + nouveau_ttm_fini(drm); fail_device: nouveau_cli_destroy(&drm->client); return ret; @@ -179,10 +304,14 @@ nouveau_drm_unload(struct drm_device *dev) struct pci_dev *pdev = dev->pdev; int ret; + nouveau_fbcon_fini(dev); + nouveau_accel_fini(drm); + ret = nouveau_unload(dev); if (ret) return ret; + nouveau_ttm_fini(drm); nouveau_agp_fini(drm); pci_set_drvdata(pdev, drm->client.base.device); @@ -193,10 +322,11 @@ nouveau_drm_unload(struct drm_device *dev) static void nouveau_drm_remove(struct pci_dev *pdev) { - struct nouveau_device *device; + struct nouveau_object *device; nouveau_pci_remove(pdev); device = pci_get_drvdata(pdev); - nouveau_device_destroy(&device); + nouveau_object_ref(NULL, &device); + nouveau_object_debug(); } int @@ -211,10 +341,23 @@ nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state) pm_state.event == PM_EVENT_PRETHAW) return 0; + NV_INFO(drm, "suspending fbcon...\n"); + nouveau_fbcon_set_suspend(dev, 1); + + NV_INFO(drm, "suspending drm...\n"); ret = nouveau_pci_suspend(pdev, pm_state); if (ret) return ret; + NV_INFO(drm, "evicting buffers...\n"); + ttm_bo_evict_mm(&drm->ttm.bdev, TTM_PL_VRAM); + + if (drm->fence && nouveau_fence(drm)->suspend) { + if (!nouveau_fence(drm)->suspend(drm)) + return -ENOMEM; + } + + NV_INFO(drm, "suspending client object trees...\n"); list_for_each_entry(cli, &drm->clients, head) { ret = nouveau_client_fini(&cli->base, true); if (ret) @@ -255,6 +398,7 @@ nouveau_drm_resume(struct pci_dev *pdev) if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; + NV_INFO(drm, "re-enabling device...\n"); pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); ret = pci_enable_device(pdev); @@ -264,17 +408,70 @@ nouveau_drm_resume(struct pci_dev *pdev) nouveau_agp_reset(drm); + NV_INFO(drm, "resuming client object trees...\n"); nouveau_client_init(&drm->client.base); + nouveau_agp_init(drm); list_for_each_entry(cli, &drm->clients, head) { nouveau_client_init(&cli->base); } - nouveau_agp_init(drm); + if (drm->fence && nouveau_fence(drm)->resume) + nouveau_fence(drm)->resume(drm); return nouveau_pci_resume(pdev); } +int +nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) +{ + struct pci_dev *pdev = dev->pdev; + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_cli *cli; + int ret; + + ret = nouveau_cli_create(pdev, fpriv->pid, sizeof(*cli), (void **)&cli); + if (ret) + return ret; + + if (nv_device(drm->device)->card_type >= NV_50) { + ret = nouveau_vm_new(nv_device(drm->device), 0, (1ULL << 40), + 0x1000, &cli->base.vm); + if (ret) { + nouveau_cli_destroy(cli); + return ret; + } + } + + fpriv->driver_priv = cli; + + mutex_lock(&drm->client.mutex); + list_add(&cli->head, &drm->clients); + mutex_unlock(&drm->client.mutex); + return 0; +} + +void +nouveau_drm_preclose(struct drm_device *dev, struct drm_file *fpriv) +{ + struct nouveau_cli *cli = nouveau_cli(fpriv); + struct nouveau_drm *drm = nouveau_drm(dev); + + if (cli->abi16) + nouveau_abi16_fini(cli->abi16); + + mutex_lock(&drm->client.mutex); + list_del(&cli->head); + mutex_unlock(&drm->client.mutex); +} + +void +nouveau_drm_postclose(struct drm_device *dev, struct drm_file *fpriv) +{ + struct nouveau_cli *cli = nouveau_cli(fpriv); + nouveau_cli_destroy(cli); +} + static struct pci_device_id nouveau_drm_pci_table[] = { { -- cgit From 77145f1cbdf8d28b46ff8070ca749bad821e0774 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 31 Jul 2012 16:16:21 +1000 Subject: drm/nouveau: port remainder of drm code, and rip out compat layer v2: Ben Skeggs - fill in nouveau_pm.dev to prevent oops - fix ppc issues (build + OF shadow) Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drm.c | 227 ++++++++++++++++++++++++++++------ 1 file changed, 190 insertions(+), 37 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nouveau_drm.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 92ecf50a39d3..8b508cec65a2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ +#include #include #include @@ -34,24 +35,22 @@ #include #include "nouveau_drm.h" +#include "nouveau_irq.h" #include "nouveau_dma.h" +#include "nouveau_ttm.h" +#include "nouveau_gem.h" #include "nouveau_agp.h" +#include "nouveau_vga.h" +#include "nouveau_pm.h" +#include "nouveau_acpi.h" +#include "nouveau_bios.h" +#include "nouveau_ioctl.h" #include "nouveau_abi16.h" #include "nouveau_fbcon.h" #include "nouveau_fence.h" #include "nouveau_ttm.h" -int __devinit nouveau_pci_probe(struct pci_dev *, const struct pci_device_id *); -void nouveau_pci_remove(struct pci_dev *); -int nouveau_pci_suspend(struct pci_dev *, pm_message_t); -int nouveau_pci_resume(struct pci_dev *); -int __init nouveau_init(struct pci_driver *); -void __exit nouveau_exit(struct pci_driver *); - -int nouveau_load(struct drm_device *, unsigned long); -int nouveau_unload(struct drm_device *); - MODULE_PARM_DESC(config, "option string to pass to driver core"); static char *nouveau_config; module_param_named(config, nouveau_config, charp, 0400); @@ -64,6 +63,12 @@ MODULE_PARM_DESC(noaccel, "disable kernel/abi16 acceleration"); static int nouveau_noaccel = 0; module_param_named(noaccel, nouveau_noaccel, int, 0400); +MODULE_PARM_DESC(modeset, "enable driver"); +int nouveau_modeset = -1; +module_param_named(modeset, nouveau_modeset, int, 0400); + +static struct drm_driver driver; + static u64 nouveau_name(struct pci_dev *pdev) { @@ -206,7 +211,7 @@ nouveau_drm_probe(struct pci_dev *pdev, const struct pci_device_id *pent) pci_set_master(pdev); - ret = nouveau_pci_probe(pdev, pent); + ret = drm_get_pci_dev(pdev, pent, &driver); if (ret) { nouveau_object_ref(NULL, (struct nouveau_object **)&device); return ret; @@ -224,13 +229,14 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) int ret; ret = nouveau_cli_create(pdev, 0, sizeof(*drm), (void**)&drm); - dev->dev_private = drm; if (ret) return ret; + dev->dev_private = drm; + drm->dev = dev; + INIT_LIST_HEAD(&drm->clients); spin_lock_init(&drm->tile.lock); - drm->dev = dev; /* make sure AGP controller is in a consistent state before we * (possibly) execute vbios init tables (see nouveau_agp.h) @@ -266,9 +272,15 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) if (ret) goto fail_device; + /* workaround an odd issue on nvc1 by disabling the device's + * nosnoop capability. hopefully won't cause issues until a + * better fix is found - assuming there is one... + */ device = nv_device(drm->device); + if (nv_device(drm->device)->chipset == 0xc1) + nv_mask(device, 0x00088080, 0x00000800, 0x00000000); - /* initialise AGP */ + nouveau_vga_init(drm); nouveau_agp_init(drm); if (device->card_type >= NV_50) { @@ -280,18 +292,43 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) ret = nouveau_ttm_init(drm); if (ret) - goto fail_device; + goto fail_ttm; + + ret = nouveau_bios_init(dev); + if (ret) + goto fail_bios; + + ret = nouveau_irq_init(dev); + if (ret) + goto fail_irq; - ret = nouveau_load(dev, flags); + ret = nouveau_display_create(dev); if (ret) - goto fail_load; + goto fail_dispctor; + + if (dev->mode_config.num_crtc) { + ret = nouveau_display_init(dev); + if (ret) + goto fail_dispinit; + } + + nouveau_pm_init(dev); nouveau_accel_init(drm); nouveau_fbcon_init(dev); return 0; -fail_load: +fail_dispinit: + nouveau_display_destroy(dev); +fail_dispctor: + nouveau_irq_fini(dev); +fail_irq: + nouveau_bios_takedown(dev); +fail_bios: nouveau_ttm_fini(drm); +fail_ttm: + nouveau_agp_fini(drm); + nouveau_vga_fini(drm); fail_device: nouveau_cli_destroy(&drm->client); return ret; @@ -300,21 +337,23 @@ fail_device: int nouveau_drm_unload(struct drm_device *dev) { - struct nouveau_drm *drm = nouveau_newpriv(dev); - struct pci_dev *pdev = dev->pdev; - int ret; + struct nouveau_drm *drm = nouveau_drm(dev); nouveau_fbcon_fini(dev); nouveau_accel_fini(drm); - ret = nouveau_unload(dev); - if (ret) - return ret; + nouveau_pm_fini(dev); + + nouveau_display_fini(dev); + nouveau_display_destroy(dev); + + nouveau_irq_fini(dev); + nouveau_bios_takedown(dev); nouveau_ttm_fini(drm); nouveau_agp_fini(drm); + nouveau_vga_fini(drm); - pci_set_drvdata(pdev, drm->client.base.device); nouveau_cli_destroy(&drm->client); return 0; } @@ -322,9 +361,13 @@ nouveau_drm_unload(struct drm_device *dev) static void nouveau_drm_remove(struct pci_dev *pdev) { + struct drm_device *dev = pci_get_drvdata(pdev); + struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_object *device; - nouveau_pci_remove(pdev); - device = pci_get_drvdata(pdev); + + device = drm->client.base.device; + drm_put_dev(dev); + nouveau_object_ref(NULL, &device); nouveau_object_debug(); } @@ -333,7 +376,7 @@ int nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state) { struct drm_device *dev = pci_get_drvdata(pdev); - struct nouveau_drm *drm = nouveau_newpriv(dev); + struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_cli *cli; int ret; @@ -344,8 +387,8 @@ nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state) NV_INFO(drm, "suspending fbcon...\n"); nouveau_fbcon_set_suspend(dev, 1); - NV_INFO(drm, "suspending drm...\n"); - ret = nouveau_pci_suspend(pdev, pm_state); + NV_INFO(drm, "suspending display...\n"); + ret = nouveau_display_suspend(dev); if (ret) return ret; @@ -383,7 +426,8 @@ fail_client: nouveau_client_init(&cli->base); } - nouveau_pci_resume(pdev); + NV_INFO(drm, "resuming display...\n"); + nouveau_display_resume(dev); return ret; } @@ -391,7 +435,7 @@ int nouveau_drm_resume(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); - struct nouveau_drm *drm = nouveau_newpriv(dev); + struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_cli *cli; int ret; @@ -419,7 +463,13 @@ nouveau_drm_resume(struct pci_dev *pdev) if (drm->fence && nouveau_fence(drm)->resume) nouveau_fence(drm)->resume(drm); - return nouveau_pci_resume(pdev); + nouveau_run_vbios_init(dev); + nouveau_irq_postinstall(dev); + nouveau_pm_resume(dev); + + NV_INFO(drm, "resuming display...\n"); + nouveau_display_resume(dev); + return 0; } int @@ -472,6 +522,90 @@ nouveau_drm_postclose(struct drm_device *dev, struct drm_file *fpriv) nouveau_cli_destroy(cli); } +static struct drm_ioctl_desc +nouveau_ioctls[] = { + DRM_IOCTL_DEF_DRV(NOUVEAU_GETPARAM, nouveau_abi16_ioctl_getparam, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_SETPARAM, nouveau_abi16_ioctl_setparam, DRM_UNLOCKED|DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_ALLOC, nouveau_abi16_ioctl_channel_alloc, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_FREE, nouveau_abi16_ioctl_channel_free, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GROBJ_ALLOC, nouveau_abi16_ioctl_grobj_alloc, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_abi16_ioctl_notifierobj_alloc, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GPUOBJ_FREE, nouveau_abi16_ioctl_gpuobj_free, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_UNLOCKED|DRM_AUTH), +}; + +static const struct file_operations +nouveau_driver_fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .unlocked_ioctl = drm_ioctl, + .mmap = nouveau_ttm_mmap, + .poll = drm_poll, + .fasync = drm_fasync, + .read = drm_read, +#if defined(CONFIG_COMPAT) + .compat_ioctl = nouveau_compat_ioctl, +#endif + .llseek = noop_llseek, +}; + +static struct drm_driver +driver = { + .driver_features = + DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG | + DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | + DRIVER_MODESET | DRIVER_PRIME, + + .load = nouveau_drm_load, + .unload = nouveau_drm_unload, + .open = nouveau_drm_open, + .preclose = nouveau_drm_preclose, + .postclose = nouveau_drm_postclose, + .lastclose = nouveau_vga_lastclose, + + .irq_preinstall = nouveau_irq_preinstall, + .irq_postinstall = nouveau_irq_postinstall, + .irq_uninstall = nouveau_irq_uninstall, + .irq_handler = nouveau_irq_handler, + + .get_vblank_counter = drm_vblank_count, + .enable_vblank = nouveau_vblank_enable, + .disable_vblank = nouveau_vblank_disable, + + .ioctls = nouveau_ioctls, + .fops = &nouveau_driver_fops, + + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_export = nouveau_gem_prime_export, + .gem_prime_import = nouveau_gem_prime_import, + + .gem_init_object = nouveau_gem_object_new, + .gem_free_object = nouveau_gem_object_del, + .gem_open_object = nouveau_gem_object_open, + .gem_close_object = nouveau_gem_object_close, + + .dumb_create = nouveau_display_dumb_create, + .dumb_map_offset = nouveau_display_dumb_map_offset, + .dumb_destroy = nouveau_display_dumb_destroy, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, +#ifdef GIT_REVISION + .date = GIT_REVISION, +#else + .date = DRIVER_DATE, +#endif + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, +}; + static struct pci_device_id nouveau_drm_pci_table[] = { { @@ -500,19 +634,38 @@ nouveau_drm_pci_driver = { static int __init nouveau_drm_init(void) { - return nouveau_init(&nouveau_drm_pci_driver); + driver.num_ioctls = ARRAY_SIZE(nouveau_ioctls); + + if (nouveau_modeset == -1) { +#ifdef CONFIG_VGA_CONSOLE + if (vgacon_text_force()) + nouveau_modeset = 0; + else +#endif + nouveau_modeset = 1; + } + + if (!nouveau_modeset) + return 0; + + nouveau_register_dsm_handler(); + return drm_pci_init(&driver, &nouveau_drm_pci_driver); } static void __exit nouveau_drm_exit(void) { - nouveau_exit(&nouveau_drm_pci_driver); + if (!nouveau_modeset) + return; + + drm_pci_exit(&driver, &nouveau_drm_pci_driver); + nouveau_unregister_dsm_handler(); } module_init(nouveau_drm_init); module_exit(nouveau_drm_exit); MODULE_DEVICE_TABLE(pci, nouveau_drm_pci_table); -MODULE_AUTHOR("Nouveau Project"); -MODULE_DESCRIPTION("nVidia Riva/TNT/GeForce/Quadro/Tesla"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL and additional rights"); -- cgit From 49981046e3dc2f934663548a270d4bf1a4534bb9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 6 Aug 2012 19:38:25 +1000 Subject: drm/nve0: use async copy engine for ttm buffer moves if available Kepler PFIFO lost the ability to address multiple engines from a single channel, so we need a separate one for the copy engine. v2: Marcin Slusarz - regression fix: restore hw accelerated buffer copies Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drm.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nouveau_drm.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 8b508cec65a2..4dfc40e3dabe 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -109,6 +109,7 @@ nouveau_accel_fini(struct nouveau_drm *drm) { nouveau_gpuobj_ref(NULL, &drm->notify); nouveau_channel_del(&drm->channel); + nouveau_channel_del(&drm->cechan); if (drm->fence) nouveau_fence(drm)->dtor(drm); } @@ -118,6 +119,7 @@ nouveau_accel_init(struct nouveau_drm *drm) { struct nouveau_device *device = nv_device(drm->device); struct nouveau_object *object; + u32 arg0, arg1; int ret; if (nouveau_noaccel) @@ -134,8 +136,24 @@ nouveau_accel_init(struct nouveau_drm *drm) return; } + if (device->card_type >= NV_E0) { + ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE, + NVDRM_CHAN + 1, + NVE0_CHANNEL_IND_ENGINE_CE0 | + NVE0_CHANNEL_IND_ENGINE_CE1, 0, + &drm->cechan); + if (ret) + NV_ERROR(drm, "failed to create ce channel, %d\n", ret); + + arg0 = NVE0_CHANNEL_IND_ENGINE_GR; + arg1 = 0; + } else { + arg0 = NvDmaFB; + arg1 = NvDmaTT; + } + ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE, NVDRM_CHAN, - NvDmaFB, NvDmaTT, &drm->channel); + arg0, arg1, &drm->channel); if (ret) { NV_ERROR(drm, "failed to create kernel channel, %d\n", ret); nouveau_accel_fini(drm); @@ -167,7 +185,7 @@ nouveau_accel_init(struct nouveau_drm *drm) } - nouveau_bo_move_init(drm->channel); + nouveau_bo_move_init(drm); } static int __devinit -- cgit From 5b8a43aeb9cbf6b965f67f6c850382788076325a Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sun, 19 Aug 2012 23:00:00 +0200 Subject: drm/nouveau: quiet some static-related sparse noise Signed-off-by: Marcin Slusarz Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nouveau_drm.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 4dfc40e3dabe..e26358c79151 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -64,7 +64,7 @@ static int nouveau_noaccel = 0; module_param_named(noaccel, nouveau_noaccel, int, 0400); MODULE_PARM_DESC(modeset, "enable driver"); -int nouveau_modeset = -1; +static int nouveau_modeset = -1; module_param_named(modeset, nouveau_modeset, int, 0400); static struct drm_driver driver; @@ -238,7 +238,7 @@ nouveau_drm_probe(struct pci_dev *pdev, const struct pci_device_id *pent) return 0; } -int +static int nouveau_drm_load(struct drm_device *dev, unsigned long flags) { struct pci_dev *pdev = dev->pdev; @@ -352,7 +352,7 @@ fail_device: return ret; } -int +static int nouveau_drm_unload(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); @@ -490,7 +490,7 @@ nouveau_drm_resume(struct pci_dev *pdev) return 0; } -int +static int nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) { struct pci_dev *pdev = dev->pdev; @@ -519,7 +519,7 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) return 0; } -void +static void nouveau_drm_preclose(struct drm_device *dev, struct drm_file *fpriv) { struct nouveau_cli *cli = nouveau_cli(fpriv); @@ -533,7 +533,7 @@ nouveau_drm_preclose(struct drm_device *dev, struct drm_file *fpriv) mutex_unlock(&drm->client.mutex); } -void +static void nouveau_drm_postclose(struct drm_device *dev, struct drm_file *fpriv) { struct nouveau_cli *cli = nouveau_cli(fpriv); -- cgit From fa6df8c163ddf1fba658059695ab9587f344712c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 12 Sep 2012 13:09:23 +1000 Subject: drm/nouveau/core: have client-id be a string, rather than an integer Can be somewhat more informative that way... Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drm.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nouveau_drm.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index e26358c79151..e96507e11488 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -79,7 +79,8 @@ nouveau_name(struct pci_dev *pdev) } static int -nouveau_cli_create(struct pci_dev *pdev, u32 name, int size, void **pcli) +nouveau_cli_create(struct pci_dev *pdev, const char *name, + int size, void **pcli) { struct nouveau_cli *cli; int ret; @@ -246,7 +247,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) struct nouveau_drm *drm; int ret; - ret = nouveau_cli_create(pdev, 0, sizeof(*drm), (void**)&drm); + ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm); if (ret) return ret; @@ -496,9 +497,12 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) struct pci_dev *pdev = dev->pdev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_cli *cli; + char name[16]; int ret; - ret = nouveau_cli_create(pdev, fpriv->pid, sizeof(*cli), (void **)&cli); + snprintf(name, sizeof(name), "%d", fpriv->pid); + + ret = nouveau_cli_create(pdev, name, sizeof(*cli), (void **)&cli); if (ret) return ret; -- cgit