]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/nouveau/nouveau_ttm.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
[karo-tx-linux.git] / drivers / gpu / drm / nouveau / nouveau_ttm.c
index e729535e9b26b2f665cc138533176588d2a312fd..9be9cb58e19b30e6f463aaa637df067eb46ef9ac 100644 (file)
  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#include "drmP.h"
+#include <subdev/fb.h>
+#include <subdev/vm.h>
+#include <subdev/instmem.h>
 
-#include "nouveau_drv.h"
+#include "nouveau_drm.h"
+#include "nouveau_ttm.h"
+#include "nouveau_gem.h"
 
 static int
 nouveau_vram_manager_init(struct ttm_mem_type_manager *man, unsigned long psize)
@@ -60,11 +64,10 @@ static void
 nouveau_vram_manager_del(struct ttm_mem_type_manager *man,
                         struct ttm_mem_reg *mem)
 {
-       struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev);
-       struct drm_device *dev = dev_priv->dev;
-
+       struct nouveau_drm *drm = nouveau_bdev(man->bdev);
+       struct nouveau_fb *pfb = nouveau_fb(drm->device);
        nouveau_mem_node_cleanup(mem->mm_node);
-       nvfb_vram_put(dev, (struct nouveau_mem **)&mem->mm_node);
+       pfb->ram.put(pfb, (struct nouveau_mem **)&mem->mm_node);
 }
 
 static int
@@ -73,8 +76,8 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man,
                         struct ttm_placement *placement,
                         struct ttm_mem_reg *mem)
 {
-       struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev);
-       struct drm_device *dev = dev_priv->dev;
+       struct nouveau_drm *drm = nouveau_bdev(man->bdev);
+       struct nouveau_fb *pfb = nouveau_fb(drm->device);
        struct nouveau_bo *nvbo = nouveau_bo(bo);
        struct nouveau_mem *node;
        u32 size_nc = 0;
@@ -83,9 +86,9 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man,
        if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG)
                size_nc = 1 << nvbo->page_shift;
 
-       ret = nvfb_vram_get(dev, mem->num_pages << PAGE_SHIFT,
-                       mem->page_alignment << PAGE_SHIFT, size_nc,
-                       (nvbo->tile_flags >> 8) & 0x3ff, &node);
+       ret = pfb->ram.get(pfb, mem->num_pages << PAGE_SHIFT,
+                          mem->page_alignment << PAGE_SHIFT, size_nc,
+                          (nvbo->tile_flags >> 8) & 0x3ff, &node);
        if (ret) {
                mem->mm_node = NULL;
                return (ret == -ENOSPC) ? 0 : ret;
@@ -98,7 +101,7 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man,
        return 0;
 }
 
-void
+static void
 nouveau_vram_manager_debug(struct ttm_mem_type_manager *man, const char *prefix)
 {
        struct nouveau_mm *mm = man->priv;
@@ -158,11 +161,9 @@ nouveau_gart_manager_new(struct ttm_mem_type_manager *man,
                         struct ttm_placement *placement,
                         struct ttm_mem_reg *mem)
 {
-       struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
        struct nouveau_mem *node;
 
-       if (unlikely((mem->num_pages << PAGE_SHIFT) >=
-                    dev_priv->gart_info.aper_size))
+       if (unlikely((mem->num_pages << PAGE_SHIFT) >= 512 * 1024 * 1024))
                return -ENOMEM;
 
        node = kzalloc(sizeof(*node), GFP_KERNEL);
@@ -175,7 +176,7 @@ nouveau_gart_manager_new(struct ttm_mem_type_manager *man,
        return 0;
 }
 
-void
+static void
 nouveau_gart_manager_debug(struct ttm_mem_type_manager *man, const char *prefix)
 {
 }
@@ -188,13 +189,17 @@ const struct ttm_mem_type_manager_func nouveau_gart_manager = {
        nouveau_gart_manager_debug
 };
 
+#include <core/subdev/vm/nv04.h>
 static int
 nv04_gart_manager_init(struct ttm_mem_type_manager *man, unsigned long psize)
 {
-       struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev);
-       struct drm_device *dev = dev_priv->dev;
-       man->priv = nv04vm_ref(dev);
-       return (man->priv != NULL) ? 0 : -ENODEV;
+       struct nouveau_drm *drm = nouveau_bdev(man->bdev);
+       struct nouveau_vmmgr *vmm = nouveau_vmmgr(drm->device);
+       struct nv04_vmmgr_priv *priv = (void *)vmm;
+       struct nouveau_vm *vm = NULL;
+       nouveau_vm_ref(priv->vm, &vm, NULL);
+       man->priv = vm;
+       return 0;
 }
 
 static int
@@ -243,7 +248,7 @@ nv04_gart_manager_new(struct ttm_mem_type_manager *man,
        return 0;
 }
 
-void
+static void
 nv04_gart_manager_debug(struct ttm_mem_type_manager *man, const char *prefix)
 {
 }
@@ -260,13 +265,12 @@ int
 nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma)
 {
        struct drm_file *file_priv = filp->private_data;
-       struct drm_nouveau_private *dev_priv =
-               file_priv->minor->dev->dev_private;
+       struct nouveau_drm *drm = nouveau_drm(file_priv->minor->dev);
 
        if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
                return drm_mmap(filp, vma);
 
-       return ttm_bo_mmap(filp, vma, &dev_priv->ttm.bdev);
+       return ttm_bo_mmap(filp, vma, &drm->ttm.bdev);
 }
 
 static int
@@ -282,12 +286,12 @@ nouveau_ttm_mem_global_release(struct drm_global_reference *ref)
 }
 
 int
-nouveau_ttm_global_init(struct drm_nouveau_private *dev_priv)
+nouveau_ttm_global_init(struct nouveau_drm *drm)
 {
        struct drm_global_reference *global_ref;
        int ret;
 
-       global_ref = &dev_priv->ttm.mem_global_ref;
+       global_ref = &drm->ttm.mem_global_ref;
        global_ref->global_type = DRM_GLOBAL_TTM_MEM;
        global_ref->size = sizeof(struct ttm_mem_global);
        global_ref->init = &nouveau_ttm_mem_global_init;
@@ -296,12 +300,12 @@ nouveau_ttm_global_init(struct drm_nouveau_private *dev_priv)
        ret = drm_global_item_ref(global_ref);
        if (unlikely(ret != 0)) {
                DRM_ERROR("Failed setting up TTM memory accounting\n");
-               dev_priv->ttm.mem_global_ref.release = NULL;
+               drm->ttm.mem_global_ref.release = NULL;
                return ret;
        }
 
-       dev_priv->ttm.bo_global_ref.mem_glob = global_ref->object;
-       global_ref = &dev_priv->ttm.bo_global_ref.ref;
+       drm->ttm.bo_global_ref.mem_glob = global_ref->object;
+       global_ref = &drm->ttm.bo_global_ref.ref;
        global_ref->global_type = DRM_GLOBAL_TTM_BO;
        global_ref->size = sizeof(struct ttm_bo_global);
        global_ref->init = &ttm_bo_global_init;
@@ -310,8 +314,8 @@ nouveau_ttm_global_init(struct drm_nouveau_private *dev_priv)
        ret = drm_global_item_ref(global_ref);
        if (unlikely(ret != 0)) {
                DRM_ERROR("Failed setting up TTM BO subsystem\n");
-               drm_global_item_unref(&dev_priv->ttm.mem_global_ref);
-               dev_priv->ttm.mem_global_ref.release = NULL;
+               drm_global_item_unref(&drm->ttm.mem_global_ref);
+               drm->ttm.mem_global_ref.release = NULL;
                return ret;
        }
 
@@ -319,12 +323,101 @@ nouveau_ttm_global_init(struct drm_nouveau_private *dev_priv)
 }
 
 void
-nouveau_ttm_global_release(struct drm_nouveau_private *dev_priv)
+nouveau_ttm_global_release(struct nouveau_drm *drm)
 {
-       if (dev_priv->ttm.mem_global_ref.release == NULL)
+       if (drm->ttm.mem_global_ref.release == NULL)
                return;
 
-       drm_global_item_unref(&dev_priv->ttm.bo_global_ref.ref);
-       drm_global_item_unref(&dev_priv->ttm.mem_global_ref);
-       dev_priv->ttm.mem_global_ref.release = NULL;
+       drm_global_item_unref(&drm->ttm.bo_global_ref.ref);
+       drm_global_item_unref(&drm->ttm.mem_global_ref);
+       drm->ttm.mem_global_ref.release = NULL;
+}
+
+int
+nouveau_ttm_init(struct nouveau_drm *drm)
+{
+       struct drm_device *dev = drm->dev;
+       u32 bits;
+       int ret;
+
+       bits = nouveau_vmmgr(drm->device)->dma_bits;
+       if ( drm->agp.stat == ENABLED ||
+           !pci_dma_supported(dev->pdev, DMA_BIT_MASK(bits)))
+               bits = 32;
+
+       ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(bits));
+       if (ret)
+               return ret;
+
+       ret = pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(bits));
+       if (ret)
+               pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(32));
+
+       ret = nouveau_ttm_global_init(drm);
+       if (ret)
+               return ret;
+
+       ret = ttm_bo_device_init(&drm->ttm.bdev,
+                                 drm->ttm.bo_global_ref.ref.object,
+                                 &nouveau_bo_driver, DRM_FILE_PAGE_OFFSET,
+                                 bits <= 32 ? true : false);
+       if (ret) {
+               NV_ERROR(drm, "error initialising bo driver, %d\n", ret);
+               return ret;
+       }
+
+       /* VRAM init */
+       drm->gem.vram_available  = nouveau_fb(drm->device)->ram.size;
+       drm->gem.vram_available -= nouveau_instmem(drm->device)->reserved;
+
+       ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_VRAM,
+                             drm->gem.vram_available >> PAGE_SHIFT);
+       if (ret) {
+               NV_ERROR(drm, "VRAM mm init failed, %d\n", ret);
+               return ret;
+       }
+
+       drm->ttm.mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1),
+                                    pci_resource_len(dev->pdev, 1),
+                                    DRM_MTRR_WC);
+
+       /* GART init */
+       if (drm->agp.stat != ENABLED) {
+               drm->gem.gart_available = nouveau_vmmgr(drm->device)->limit;
+               if (drm->gem.gart_available > 512 * 1024 * 1024)
+                       drm->gem.gart_available = 512 * 1024 * 1024;
+       } else {
+               drm->gem.gart_available = drm->agp.size;
+       }
+
+       ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_TT,
+                             drm->gem.gart_available >> PAGE_SHIFT);
+       if (ret) {
+               NV_ERROR(drm, "GART mm init failed, %d\n", ret);
+               return ret;
+       }
+
+       NV_INFO(drm, "VRAM: %d MiB\n", (u32)(drm->gem.vram_available >> 20));
+       NV_INFO(drm, "GART: %d MiB\n", (u32)(drm->gem.gart_available >> 20));
+       return 0;
+}
+
+void
+nouveau_ttm_fini(struct nouveau_drm *drm)
+{
+       mutex_lock(&drm->dev->struct_mutex);
+       ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_VRAM);
+       ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_TT);
+       mutex_unlock(&drm->dev->struct_mutex);
+
+       ttm_bo_device_release(&drm->ttm.bdev);
+
+       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;
+       }
 }