diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r-- | drivers/gpu/drm/nouveau/Kconfig | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_abi16.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.c | 103 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drm.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fbcon.c | 23 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_gem.c | 43 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_gem.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_prime.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_ttm.c | 13 |
9 files changed, 109 insertions, 92 deletions
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig index a7ff6d5a34b9..ff80f12480ea 100644 --- a/drivers/gpu/drm/nouveau/Kconfig +++ b/drivers/gpu/drm/nouveau/Kconfig @@ -15,6 +15,13 @@ config DRM_NOUVEAU select ACPI_WMI if ACPI && X86 select MXM_WMI if ACPI && X86 select POWER_SUPPLY + # Similar to i915, we need to select ACPI_VIDEO and it's dependencies + select BACKLIGHT_LCD_SUPPORT if ACPI && X86 + select BACKLIGHT_CLASS_DEVICE if ACPI && X86 + select VIDEO_OUTPUT_CONTROL if ACPI && X86 + select INPUT if ACPI && X86 + select THERMAL if ACPI && X86 + select ACPI_VIDEO if ACPI && X86 help Choose this option for open-source nVidia support. diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 1c4c6c9161ac..8f467e7bfd19 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -129,6 +129,7 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16, if (chan->ntfy) { nouveau_bo_vma_del(chan->ntfy, &chan->ntfy_vma); + nouveau_bo_unpin(chan->ntfy); drm_gem_object_unreference_unlocked(chan->ntfy->gem); } diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 0b6c296e6ef3..708b2d1c0037 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -26,6 +26,7 @@ #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> +#include <drm/ttm/ttm_execbuf_util.h> #include "nouveau_fbcon.h" #include "dispnv04/hw.h" @@ -462,51 +463,6 @@ nouveau_display_resume(struct drm_device *dev) } static int -nouveau_page_flip_reserve(struct nouveau_bo *old_bo, - struct nouveau_bo *new_bo) -{ - int ret; - - ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM); - if (ret) - return ret; - - ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0); - if (ret) - goto fail; - - if (likely(old_bo != new_bo)) { - ret = ttm_bo_reserve(&old_bo->bo, false, false, false, 0); - if (ret) - goto fail_unreserve; - } - - return 0; - -fail_unreserve: - ttm_bo_unreserve(&new_bo->bo); -fail: - nouveau_bo_unpin(new_bo); - return ret; -} - -static void -nouveau_page_flip_unreserve(struct nouveau_bo *old_bo, - struct nouveau_bo *new_bo, - struct nouveau_fence *fence) -{ - nouveau_bo_fence(new_bo, fence); - ttm_bo_unreserve(&new_bo->bo); - - if (likely(old_bo != new_bo)) { - nouveau_bo_fence(old_bo, fence); - ttm_bo_unreserve(&old_bo->bo); - } - - nouveau_bo_unpin(old_bo); -} - -static int nouveau_page_flip_emit(struct nouveau_channel *chan, struct nouveau_bo *old_bo, struct nouveau_bo *new_bo, @@ -568,6 +524,9 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct nouveau_page_flip_state *s; struct nouveau_channel *chan = NULL; struct nouveau_fence *fence; + struct list_head res; + struct ttm_validate_buffer res_val[2]; + struct ww_acquire_ctx ticket; int ret; if (!drm->channel) @@ -577,25 +536,43 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, if (!s) return -ENOMEM; - /* Don't let the buffers go away while we flip */ - ret = nouveau_page_flip_reserve(old_bo, new_bo); - if (ret) - goto fail_free; - - /* Initialize a page flip struct */ - *s = (struct nouveau_page_flip_state) - { { }, event, nouveau_crtc(crtc)->index, - fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y, - new_bo->bo.offset }; - /* Choose the channel the flip will be handled in */ + spin_lock(&old_bo->bo.bdev->fence_lock); fence = new_bo->bo.sync_obj; if (fence) chan = fence->channel; if (!chan) chan = drm->channel; + spin_unlock(&old_bo->bo.bdev->fence_lock); + mutex_lock(&chan->cli->mutex); + if (new_bo != old_bo) { + ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM); + if (likely(!ret)) { + res_val[0].bo = &old_bo->bo; + res_val[1].bo = &new_bo->bo; + INIT_LIST_HEAD(&res); + list_add_tail(&res_val[0].head, &res); + list_add_tail(&res_val[1].head, &res); + ret = ttm_eu_reserve_buffers(&ticket, &res); + if (ret) + nouveau_bo_unpin(new_bo); + } + } else + ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0); + + if (ret) { + mutex_unlock(&chan->cli->mutex); + goto fail_free; + } + + /* Initialize a page flip struct */ + *s = (struct nouveau_page_flip_state) + { { }, event, nouveau_crtc(crtc)->index, + fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y, + new_bo->bo.offset }; + /* Emit a page flip */ if (nv_device(drm->device)->card_type >= NV_50) { ret = nv50_display_flip_next(crtc, fb, chan, 0); @@ -613,12 +590,22 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, /* Update the crtc struct and cleanup */ crtc->fb = fb; - nouveau_page_flip_unreserve(old_bo, new_bo, fence); + if (old_bo != new_bo) { + ttm_eu_fence_buffer_objects(&ticket, &res, fence); + nouveau_bo_unpin(old_bo); + } else { + nouveau_bo_fence(new_bo, fence); + ttm_bo_unreserve(&new_bo->bo); + } nouveau_fence_unref(&fence); return 0; fail_unreserve: - nouveau_page_flip_unreserve(old_bo, new_bo, NULL); + if (old_bo != new_bo) { + ttm_eu_backoff_reservation(&ticket, &res); + nouveau_bo_unpin(new_bo); + } else + ttm_bo_unreserve(&new_bo->bo); fail_free: kfree(s); return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 383f4e6ea9d1..218a4b522fe5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -702,6 +702,7 @@ driver = { .gem_prime_export = drm_gem_prime_export, .gem_prime_import = drm_gem_prime_import, .gem_prime_pin = nouveau_gem_prime_pin, + .gem_prime_unpin = nouveau_gem_prime_unpin, .gem_prime_get_sg_table = nouveau_gem_prime_get_sg_table, .gem_prime_import_sg_table = nouveau_gem_prime_import_sg_table, .gem_prime_vmap = nouveau_gem_prime_vmap, diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 51fe6406edab..9352010030e9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -289,16 +289,13 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM); if (ret) { NV_ERROR(drm, "failed to pin fb: %d\n", ret); - nouveau_bo_ref(NULL, &nvbo); - goto out; + goto out_unref; } ret = nouveau_bo_map(nvbo); if (ret) { NV_ERROR(drm, "failed to map fb: %d\n", ret); - nouveau_bo_unpin(nvbo); - nouveau_bo_ref(NULL, &nvbo); - goto out; + goto out_unpin; } chan = nouveau_nofbaccel ? NULL : drm->channel; @@ -316,13 +313,14 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, info = framebuffer_alloc(0, &pdev->dev); if (!info) { ret = -ENOMEM; - goto out_unref; + goto out_unlock; } ret = fb_alloc_cmap(&info->cmap, 256, 0); if (ret) { ret = -ENOMEM; - goto out_unref; + framebuffer_release(info); + goto out_unlock; } info->par = fbcon; @@ -337,7 +335,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, fbcon->helper.fbdev = info; strcpy(info->fix.id, "nouveaufb"); - if (nouveau_nofbaccel) + if (!chan) info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_DISABLED; else info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA | @@ -383,8 +381,14 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, vga_switcheroo_client_fb_set(dev->pdev, info); return 0; -out_unref: +out_unlock: mutex_unlock(&dev->struct_mutex); + if (chan) + nouveau_bo_vma_del(nvbo, &fbcon->nouveau_fb.vma); +out_unpin: + nouveau_bo_unpin(nvbo); +out_unref: + nouveau_bo_ref(NULL, &nvbo); out: return ret; } @@ -413,6 +417,7 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon) if (nouveau_fb->nvbo) { nouveau_bo_unmap(nouveau_fb->nvbo); nouveau_bo_vma_del(nouveau_fb->nvbo, &nouveau_fb->vma); + nouveau_bo_unpin(nouveau_fb->nvbo); drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); nouveau_fb->nvbo = NULL; } diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index c0e324b557c1..e72d09c068a8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -50,7 +50,8 @@ nouveau_gem_object_del(struct drm_gem_object *gem) return; nvbo->gem = NULL; - if (unlikely(nvbo->pin_refcnt)) { + /* Lockdep hates you for doing reserve with gem object lock held */ + if (WARN_ON_ONCE(nvbo->pin_refcnt)) { nvbo->pin_refcnt = 1; nouveau_bo_unpin(nvbo); } @@ -309,10 +310,12 @@ struct validate_op { struct list_head vram_list; struct list_head gart_list; struct list_head both_list; + struct ww_acquire_ctx ticket; }; static void -validate_fini_list(struct list_head *list, struct nouveau_fence *fence) +validate_fini_list(struct list_head *list, struct nouveau_fence *fence, + struct ww_acquire_ctx *ticket) { struct list_head *entry, *tmp; struct nouveau_bo *nvbo; @@ -329,17 +332,24 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence) list_del(&nvbo->entry); nvbo->reserved_by = NULL; - ttm_bo_unreserve(&nvbo->bo); + ttm_bo_unreserve_ticket(&nvbo->bo, ticket); drm_gem_object_unreference_unlocked(nvbo->gem); } } static void -validate_fini(struct validate_op *op, struct nouveau_fence* fence) +validate_fini_no_ticket(struct validate_op *op, struct nouveau_fence *fence) { - validate_fini_list(&op->vram_list, fence); - validate_fini_list(&op->gart_list, fence); - validate_fini_list(&op->both_list, fence); + validate_fini_list(&op->vram_list, fence, &op->ticket); + validate_fini_list(&op->gart_list, fence, &op->ticket); + validate_fini_list(&op->both_list, fence, &op->ticket); +} + +static void +validate_fini(struct validate_op *op, struct nouveau_fence *fence) +{ + validate_fini_no_ticket(op, fence); + ww_acquire_fini(&op->ticket); } static int @@ -349,13 +359,11 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv, { struct nouveau_cli *cli = nouveau_cli(file_priv); struct drm_device *dev = chan->drm->dev; - struct nouveau_drm *drm = nouveau_drm(dev); - uint32_t sequence; int trycnt = 0; int ret, i; struct nouveau_bo *res_bo = NULL; - sequence = atomic_add_return(1, &drm->ttm.validate_sequence); + ww_acquire_init(&op->ticket, &reservation_ww_class); retry: if (++trycnt > 100000) { NV_ERROR(cli, "%s failed and gave up.\n", __func__); @@ -370,6 +378,7 @@ retry: gem = drm_gem_object_lookup(dev, file_priv, b->handle); if (!gem) { NV_ERROR(cli, "Unknown handle 0x%08x\n", b->handle); + ww_acquire_done(&op->ticket); validate_fini(op, NULL); return -ENOENT; } @@ -384,21 +393,23 @@ retry: NV_ERROR(cli, "multiple instances of buffer %d on " "validation list\n", b->handle); drm_gem_object_unreference_unlocked(gem); + ww_acquire_done(&op->ticket); validate_fini(op, NULL); return -EINVAL; } - ret = ttm_bo_reserve(&nvbo->bo, true, false, true, sequence); + ret = ttm_bo_reserve(&nvbo->bo, true, false, true, &op->ticket); if (ret) { - validate_fini(op, NULL); - if (unlikely(ret == -EAGAIN)) { - sequence = atomic_add_return(1, &drm->ttm.validate_sequence); + validate_fini_no_ticket(op, NULL); + if (unlikely(ret == -EDEADLK)) { ret = ttm_bo_reserve_slowpath(&nvbo->bo, true, - sequence); + &op->ticket); if (!ret) res_bo = nvbo; } if (unlikely(ret)) { + ww_acquire_done(&op->ticket); + ww_acquire_fini(&op->ticket); drm_gem_object_unreference_unlocked(gem); if (ret != -ERESTARTSYS) NV_ERROR(cli, "fail reserve\n"); @@ -422,6 +433,7 @@ retry: NV_ERROR(cli, "invalid valid domains: 0x%08x\n", b->valid_domains); list_add_tail(&nvbo->entry, &op->both_list); + ww_acquire_done(&op->ticket); validate_fini(op, NULL); return -EINVAL; } @@ -429,6 +441,7 @@ retry: goto retry; } + ww_acquire_done(&op->ticket); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.h b/drivers/gpu/drm/nouveau/nouveau_gem.h index 8d7a3f0aeb86..502e4290aa8f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.h +++ b/drivers/gpu/drm/nouveau/nouveau_gem.h @@ -36,6 +36,7 @@ extern int nouveau_gem_ioctl_info(struct drm_device *, void *, struct drm_file *); extern int nouveau_gem_prime_pin(struct drm_gem_object *); +extern void nouveau_gem_prime_unpin(struct drm_gem_object *); extern struct sg_table *nouveau_gem_prime_get_sg_table(struct drm_gem_object *); extern struct drm_gem_object *nouveau_gem_prime_import_sg_table( struct drm_device *, size_t size, struct sg_table *); diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c index f53e10874cae..e90468d5e5c0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_prime.c +++ b/drivers/gpu/drm/nouveau/nouveau_prime.c @@ -84,7 +84,7 @@ struct drm_gem_object *nouveau_gem_prime_import_sg_table(struct drm_device *dev, int nouveau_gem_prime_pin(struct drm_gem_object *obj) { struct nouveau_bo *nvbo = nouveau_gem_object(obj); - int ret = 0; + int ret; /* pin buffer into GTT */ ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_TT); @@ -93,3 +93,10 @@ int nouveau_gem_prime_pin(struct drm_gem_object *obj) return 0; } + +void nouveau_gem_prime_unpin(struct drm_gem_object *obj) +{ + struct nouveau_bo *nvbo = nouveau_gem_object(obj); + + nouveau_bo_unpin(nvbo); +} diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index d0382f7e86c8..19e3757291fb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -393,9 +393,8 @@ nouveau_ttm_init(struct nouveau_drm *drm) return ret; } - drm->ttm.mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1), - pci_resource_len(dev->pdev, 1), - DRM_MTRR_WC); + drm->ttm.mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 1), + pci_resource_len(dev->pdev, 1)); /* GART init */ if (drm->agp.stat != ENABLED) { @@ -428,10 +427,6 @@ nouveau_ttm_fini(struct nouveau_drm *drm) nouveau_ttm_global_release(drm); - if (drm->ttm.mtrr >= 0) { - drm_mtrr_del(drm->ttm.mtrr, - pci_resource_start(drm->dev->pdev, 1), - pci_resource_len(drm->dev->pdev, 1), DRM_MTRR_WC); - drm->ttm.mtrr = -1; - } + arch_phys_wc_del(drm->ttm.mtrr); + drm->ttm.mtrr = 0; } |