1a61127c2SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2e32681d6SAlan Cox /* 3e32681d6SAlan Cox * psb GEM interface 4e32681d6SAlan Cox * 5e32681d6SAlan Cox * Copyright (c) 2011, Intel Corporation. 6e32681d6SAlan Cox * 7e32681d6SAlan Cox * Authors: Alan Cox 8e32681d6SAlan Cox * 9e32681d6SAlan Cox * TODO: 10e32681d6SAlan Cox * - we need to work out if the MMU is relevant (eg for 11e32681d6SAlan Cox * accelerated operations on a GEM object) 12e32681d6SAlan Cox */ 13e32681d6SAlan Cox 140c7b178aSSam Ravnborg #include <linux/pagemap.h> 150c7b178aSSam Ravnborg 1633e079bcSThomas Zimmermann #include <asm/set_memory.h> 1733e079bcSThomas Zimmermann 18e32681d6SAlan Cox #include <drm/drm.h> 190de23977SDavid Herrmann #include <drm/drm_vma_manager.h> 20d825c565SSam Ravnborg 21ce5735b6SLee Jones #include "gem.h" 22e32681d6SAlan Cox #include "psb_drv.h" 23e32681d6SAlan Cox 24*d339386cSThomas Zimmermann /* 25*d339386cSThomas Zimmermann * PSB GEM object 26*d339386cSThomas Zimmermann */ 27*d339386cSThomas Zimmermann 28f2d061edSThomas Zimmermann int psb_gem_pin(struct psb_gem_object *pobj) 291f9f6790SThomas Zimmermann { 30f2d061edSThomas Zimmermann struct drm_gem_object *obj = &pobj->base; 31f2d061edSThomas Zimmermann struct drm_device *dev = obj->dev; 321f9f6790SThomas Zimmermann struct drm_psb_private *dev_priv = to_drm_psb_private(dev); 331f9f6790SThomas Zimmermann u32 gpu_base = dev_priv->gtt.gatt_start; 340b80214bSThomas Zimmermann struct page **pages; 350b80214bSThomas Zimmermann unsigned int npages; 36e1f80341SThomas Zimmermann int ret; 371f9f6790SThomas Zimmermann 3816dad99dSThomas Zimmermann ret = dma_resv_lock(obj->resv, NULL); 3916dad99dSThomas Zimmermann if (drm_WARN_ONCE(dev, ret, "dma_resv_lock() failed, ret=%d\n", ret)) 4016dad99dSThomas Zimmermann return ret; 4116dad99dSThomas Zimmermann 42f2d061edSThomas Zimmermann if (pobj->in_gart || pobj->stolen) 430b80214bSThomas Zimmermann goto out; /* already mapped */ 440b80214bSThomas Zimmermann 45f2d061edSThomas Zimmermann pages = drm_gem_get_pages(obj); 460b80214bSThomas Zimmermann if (IS_ERR(pages)) { 470b80214bSThomas Zimmermann ret = PTR_ERR(pages); 4814e92dd1SThomas Zimmermann goto err_dma_resv_unlock; 490b80214bSThomas Zimmermann } 500b80214bSThomas Zimmermann 51f2d061edSThomas Zimmermann npages = obj->size / PAGE_SIZE; 520b80214bSThomas Zimmermann 5333e079bcSThomas Zimmermann set_pages_array_wc(pages, npages); 5433e079bcSThomas Zimmermann 55f2d061edSThomas Zimmermann psb_gtt_insert_pages(dev_priv, &pobj->resource, pages); 560b80214bSThomas Zimmermann psb_mmu_insert_pages(psb_mmu_get_default_pd(dev_priv->mmu), pages, 57f2d061edSThomas Zimmermann (gpu_base + pobj->offset), npages, 0, 0, 580b80214bSThomas Zimmermann PSB_MMU_CACHED_MEMORY); 590b80214bSThomas Zimmermann 60f2d061edSThomas Zimmermann pobj->pages = pages; 610b80214bSThomas Zimmermann 621f9f6790SThomas Zimmermann out: 63f2d061edSThomas Zimmermann ++pobj->in_gart; 6416dad99dSThomas Zimmermann dma_resv_unlock(obj->resv); 650b80214bSThomas Zimmermann 660b80214bSThomas Zimmermann return 0; 670b80214bSThomas Zimmermann 6814e92dd1SThomas Zimmermann err_dma_resv_unlock: 6916dad99dSThomas Zimmermann dma_resv_unlock(obj->resv); 701f9f6790SThomas Zimmermann return ret; 711f9f6790SThomas Zimmermann } 721f9f6790SThomas Zimmermann 73f2d061edSThomas Zimmermann void psb_gem_unpin(struct psb_gem_object *pobj) 741f9f6790SThomas Zimmermann { 75f2d061edSThomas Zimmermann struct drm_gem_object *obj = &pobj->base; 76f2d061edSThomas Zimmermann struct drm_device *dev = obj->dev; 771f9f6790SThomas Zimmermann struct drm_psb_private *dev_priv = to_drm_psb_private(dev); 781f9f6790SThomas Zimmermann u32 gpu_base = dev_priv->gtt.gatt_start; 79de2d1822SThomas Zimmermann unsigned long npages; 8016dad99dSThomas Zimmermann int ret; 8116dad99dSThomas Zimmermann 8216dad99dSThomas Zimmermann ret = dma_resv_lock(obj->resv, NULL); 8316dad99dSThomas Zimmermann if (drm_WARN_ONCE(dev, ret, "dma_resv_lock() failed, ret=%d\n", ret)) 8416dad99dSThomas Zimmermann return; 851f9f6790SThomas Zimmermann 86f2d061edSThomas Zimmermann WARN_ON(!pobj->in_gart); 871f9f6790SThomas Zimmermann 88f2d061edSThomas Zimmermann --pobj->in_gart; 890b80214bSThomas Zimmermann 90f2d061edSThomas Zimmermann if (pobj->in_gart || pobj->stolen) 910b80214bSThomas Zimmermann goto out; 920b80214bSThomas Zimmermann 93de2d1822SThomas Zimmermann npages = obj->size / PAGE_SIZE; 94de2d1822SThomas Zimmermann 951f9f6790SThomas Zimmermann psb_mmu_remove_pages(psb_mmu_get_default_pd(dev_priv->mmu), 96de2d1822SThomas Zimmermann (gpu_base + pobj->offset), npages, 0, 0); 97f2d061edSThomas Zimmermann psb_gtt_remove_pages(dev_priv, &pobj->resource); 981f9f6790SThomas Zimmermann 9933e079bcSThomas Zimmermann /* Reset caching flags */ 100de2d1822SThomas Zimmermann set_pages_array_wb(pobj->pages, npages); 10133e079bcSThomas Zimmermann 102f2d061edSThomas Zimmermann drm_gem_put_pages(obj, pobj->pages, true, false); 103f2d061edSThomas Zimmermann pobj->pages = NULL; 1040b80214bSThomas Zimmermann 1050b80214bSThomas Zimmermann out: 10616dad99dSThomas Zimmermann dma_resv_unlock(obj->resv); 1071f9f6790SThomas Zimmermann } 1081f9f6790SThomas Zimmermann 1097cd467d0SThomas Zimmermann static vm_fault_t psb_gem_fault(struct vm_fault *vmf); 1107cd467d0SThomas Zimmermann 1117cd467d0SThomas Zimmermann static void psb_gem_free_object(struct drm_gem_object *obj) 112e32681d6SAlan Cox { 113f2d061edSThomas Zimmermann struct psb_gem_object *pobj = to_psb_gem_object(obj); 1144d46259fSLaurent Pinchart 1154d46259fSLaurent Pinchart drm_gem_object_release(obj); 1164d46259fSLaurent Pinchart 1173c101135SThomas Zimmermann /* Undo the mmap pin if we are destroying the object */ 118f2d061edSThomas Zimmermann if (pobj->mmapping) 119f2d061edSThomas Zimmermann psb_gem_unpin(pobj); 1203c101135SThomas Zimmermann 121f2d061edSThomas Zimmermann WARN_ON(pobj->in_gart && !pobj->stolen); 1223c101135SThomas Zimmermann 123f2d061edSThomas Zimmermann release_resource(&pobj->resource); 124f2d061edSThomas Zimmermann kfree(pobj); 125e32681d6SAlan Cox } 126e32681d6SAlan Cox 1277cd467d0SThomas Zimmermann static const struct vm_operations_struct psb_gem_vm_ops = { 1287cd467d0SThomas Zimmermann .fault = psb_gem_fault, 1297cd467d0SThomas Zimmermann .open = drm_gem_vm_open, 1307cd467d0SThomas Zimmermann .close = drm_gem_vm_close, 1317cd467d0SThomas Zimmermann }; 1327cd467d0SThomas Zimmermann 133957a2d0eSThomas Zimmermann static const struct drm_gem_object_funcs psb_gem_object_funcs = { 1347cd467d0SThomas Zimmermann .free = psb_gem_free_object, 1357cd467d0SThomas Zimmermann .vm_ops = &psb_gem_vm_ops, 1367cd467d0SThomas Zimmermann }; 1377cd467d0SThomas Zimmermann 138f2d061edSThomas Zimmermann struct psb_gem_object * 139576d4d2dSThomas Zimmermann psb_gem_create(struct drm_device *dev, u64 size, const char *name, bool stolen, u32 align) 140e32681d6SAlan Cox { 1413c101135SThomas Zimmermann struct drm_psb_private *dev_priv = to_drm_psb_private(dev); 142f2d061edSThomas Zimmermann struct psb_gem_object *pobj; 143576d4d2dSThomas Zimmermann struct drm_gem_object *obj; 144e32681d6SAlan Cox int ret; 145e32681d6SAlan Cox 146e32681d6SAlan Cox size = roundup(size, PAGE_SIZE); 147e32681d6SAlan Cox 148f2d061edSThomas Zimmermann pobj = kzalloc(sizeof(*pobj), GFP_KERNEL); 149f2d061edSThomas Zimmermann if (!pobj) 1503c101135SThomas Zimmermann return ERR_PTR(-ENOMEM); 151f2d061edSThomas Zimmermann obj = &pobj->base; 152576d4d2dSThomas Zimmermann 1533c101135SThomas Zimmermann /* GTT resource */ 1543c101135SThomas Zimmermann 155f2d061edSThomas Zimmermann ret = psb_gtt_allocate_resource(dev_priv, &pobj->resource, name, size, align, stolen, 156f2d061edSThomas Zimmermann &pobj->offset); 1573c101135SThomas Zimmermann if (ret) 1583c101135SThomas Zimmermann goto err_kfree; 1593c101135SThomas Zimmermann 1603c101135SThomas Zimmermann if (stolen) { 161f2d061edSThomas Zimmermann pobj->stolen = true; 162f2d061edSThomas Zimmermann pobj->in_gart = 1; 1633c101135SThomas Zimmermann } 1643c101135SThomas Zimmermann 1653c101135SThomas Zimmermann /* GEM object */ 1663c101135SThomas Zimmermann 167576d4d2dSThomas Zimmermann obj->funcs = &psb_gem_object_funcs; 168576d4d2dSThomas Zimmermann 169957a2d0eSThomas Zimmermann if (stolen) { 170957a2d0eSThomas Zimmermann drm_gem_private_object_init(dev, obj, size); 171957a2d0eSThomas Zimmermann } else { 172576d4d2dSThomas Zimmermann ret = drm_gem_object_init(dev, obj, size); 173576d4d2dSThomas Zimmermann if (ret) 1743c101135SThomas Zimmermann goto err_release_resource; 175576d4d2dSThomas Zimmermann 176576d4d2dSThomas Zimmermann /* Limit the object to 32-bit mappings */ 177576d4d2dSThomas Zimmermann mapping_set_gfp_mask(obj->filp->f_mapping, GFP_KERNEL | __GFP_DMA32); 178957a2d0eSThomas Zimmermann } 179576d4d2dSThomas Zimmermann 180f2d061edSThomas Zimmermann return pobj; 181576d4d2dSThomas Zimmermann 1823c101135SThomas Zimmermann err_release_resource: 183f2d061edSThomas Zimmermann release_resource(&pobj->resource); 1843c101135SThomas Zimmermann err_kfree: 185f2d061edSThomas Zimmermann kfree(pobj); 186576d4d2dSThomas Zimmermann return ERR_PTR(ret); 187e32681d6SAlan Cox } 188e32681d6SAlan Cox 189e32681d6SAlan Cox /** 190e32681d6SAlan Cox * psb_gem_dumb_create - create a dumb buffer 19192bd69c7SLee Jones * @file: our client file 192e32681d6SAlan Cox * @dev: our device 193e32681d6SAlan Cox * @args: the requested arguments copied from userspace 194e32681d6SAlan Cox * 195e32681d6SAlan Cox * Allocate a buffer suitable for use for a frame buffer of the 196e32681d6SAlan Cox * form described by user space. Give userspace a handle by which 197e32681d6SAlan Cox * to reference it. 198e32681d6SAlan Cox */ 199e32681d6SAlan Cox int psb_gem_dumb_create(struct drm_file *file, struct drm_device *dev, 200e32681d6SAlan Cox struct drm_mode_create_dumb *args) 201e32681d6SAlan Cox { 202576d4d2dSThomas Zimmermann size_t pitch, size; 203f2d061edSThomas Zimmermann struct psb_gem_object *pobj; 204576d4d2dSThomas Zimmermann struct drm_gem_object *obj; 205576d4d2dSThomas Zimmermann u32 handle; 206576d4d2dSThomas Zimmermann int ret; 207576d4d2dSThomas Zimmermann 208576d4d2dSThomas Zimmermann pitch = args->width * DIV_ROUND_UP(args->bpp, 8); 209576d4d2dSThomas Zimmermann pitch = ALIGN(pitch, 64); 210576d4d2dSThomas Zimmermann 211576d4d2dSThomas Zimmermann size = pitch * args->height; 212576d4d2dSThomas Zimmermann size = roundup(size, PAGE_SIZE); 213576d4d2dSThomas Zimmermann if (!size) 214576d4d2dSThomas Zimmermann return -EINVAL; 215576d4d2dSThomas Zimmermann 216f2d061edSThomas Zimmermann pobj = psb_gem_create(dev, size, "gem", false, PAGE_SIZE); 217f2d061edSThomas Zimmermann if (IS_ERR(pobj)) 218f2d061edSThomas Zimmermann return PTR_ERR(pobj); 219f2d061edSThomas Zimmermann obj = &pobj->base; 220576d4d2dSThomas Zimmermann 221576d4d2dSThomas Zimmermann ret = drm_gem_handle_create(file, obj, &handle); 222576d4d2dSThomas Zimmermann if (ret) 223576d4d2dSThomas Zimmermann goto err_drm_gem_object_put; 224576d4d2dSThomas Zimmermann 225576d4d2dSThomas Zimmermann drm_gem_object_put(obj); 226576d4d2dSThomas Zimmermann 227576d4d2dSThomas Zimmermann args->pitch = pitch; 228576d4d2dSThomas Zimmermann args->size = size; 229576d4d2dSThomas Zimmermann args->handle = handle; 230576d4d2dSThomas Zimmermann 231576d4d2dSThomas Zimmermann return 0; 232576d4d2dSThomas Zimmermann 233576d4d2dSThomas Zimmermann err_drm_gem_object_put: 234576d4d2dSThomas Zimmermann drm_gem_object_put(obj); 235576d4d2dSThomas Zimmermann return ret; 236e32681d6SAlan Cox } 237e32681d6SAlan Cox 238e32681d6SAlan Cox /** 239e32681d6SAlan Cox * psb_gem_fault - pagefault handler for GEM objects 240e32681d6SAlan Cox * @vmf: fault detail 241e32681d6SAlan Cox * 242e32681d6SAlan Cox * Invoked when a fault occurs on an mmap of a GEM managed area. GEM 243e32681d6SAlan Cox * does most of the work for us including the actual map/unmap calls 244e32681d6SAlan Cox * but we need to do the actual page work. 245e32681d6SAlan Cox * 246e32681d6SAlan Cox * This code eventually needs to handle faulting objects in and out 247e32681d6SAlan Cox * of the GTT and repacking it when we run out of space. We can put 248e32681d6SAlan Cox * that off for now and for our simple uses 249e32681d6SAlan Cox * 250e32681d6SAlan Cox * The VMA was set up by GEM. In doing so it also ensured that the 251e32681d6SAlan Cox * vma->vm_private_data points to the GEM object that is backing this 252e32681d6SAlan Cox * mapping. 253e32681d6SAlan Cox */ 2547cd467d0SThomas Zimmermann static vm_fault_t psb_gem_fault(struct vm_fault *vmf) 255e32681d6SAlan Cox { 25611bac800SDave Jiang struct vm_area_struct *vma = vmf->vma; 257e32681d6SAlan Cox struct drm_gem_object *obj; 258f2d061edSThomas Zimmermann struct psb_gem_object *pobj; 2590edf6813SSouptick Joarder int err; 2600edf6813SSouptick Joarder vm_fault_t ret; 261e32681d6SAlan Cox unsigned long pfn; 262e32681d6SAlan Cox pgoff_t page_offset; 263e32681d6SAlan Cox struct drm_device *dev; 264e32681d6SAlan Cox struct drm_psb_private *dev_priv; 265e32681d6SAlan Cox 266e32681d6SAlan Cox obj = vma->vm_private_data; /* GEM object */ 267e32681d6SAlan Cox dev = obj->dev; 268f71635e8SThomas Zimmermann dev_priv = to_drm_psb_private(dev); 269e32681d6SAlan Cox 270f2d061edSThomas Zimmermann pobj = to_psb_gem_object(obj); 271e32681d6SAlan Cox 272e32681d6SAlan Cox /* Make sure we don't parallel update on a fault, nor move or remove 273e32681d6SAlan Cox something from beneath our feet */ 274737292a3SDaniel Vetter mutex_lock(&dev_priv->mmap_mutex); 275e32681d6SAlan Cox 276e32681d6SAlan Cox /* For now the mmap pins the object and it stays pinned. As things 277e32681d6SAlan Cox stand that will do us no harm */ 278f2d061edSThomas Zimmermann if (pobj->mmapping == 0) { 279f2d061edSThomas Zimmermann err = psb_gem_pin(pobj); 2800edf6813SSouptick Joarder if (err < 0) { 2810edf6813SSouptick Joarder dev_err(dev->dev, "gma500: pin failed: %d\n", err); 2820edf6813SSouptick Joarder ret = vmf_error(err); 283e32681d6SAlan Cox goto fail; 284e32681d6SAlan Cox } 285f2d061edSThomas Zimmermann pobj->mmapping = 1; 286e32681d6SAlan Cox } 287e32681d6SAlan Cox 288e32681d6SAlan Cox /* Page relative to the VMA start - we must calculate this ourselves 289e32681d6SAlan Cox because vmf->pgoff is the fake GEM offset */ 2901a29d85eSJan Kara page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; 291e32681d6SAlan Cox 292e32681d6SAlan Cox /* CPU view of the page, don't go via the GART for CPU writes */ 293f2d061edSThomas Zimmermann if (pobj->stolen) 294f2d061edSThomas Zimmermann pfn = (dev_priv->stolen_base + pobj->offset) >> PAGE_SHIFT; 295e32681d6SAlan Cox else 296f2d061edSThomas Zimmermann pfn = page_to_pfn(pobj->pages[page_offset]); 2970edf6813SSouptick Joarder ret = vmf_insert_pfn(vma, vmf->address, pfn); 298e32681d6SAlan Cox fail: 299737292a3SDaniel Vetter mutex_unlock(&dev_priv->mmap_mutex); 3000edf6813SSouptick Joarder 3010edf6813SSouptick Joarder return ret; 302e32681d6SAlan Cox } 303*d339386cSThomas Zimmermann 304*d339386cSThomas Zimmermann /* 305*d339386cSThomas Zimmermann * Memory management 306*d339386cSThomas Zimmermann */ 307*d339386cSThomas Zimmermann 308*d339386cSThomas Zimmermann /* Insert vram stolen pages into the GTT. */ 309*d339386cSThomas Zimmermann static void psb_gem_mm_populate_stolen(struct drm_psb_private *pdev) 310*d339386cSThomas Zimmermann { 311*d339386cSThomas Zimmermann struct drm_device *dev = &pdev->dev; 312*d339386cSThomas Zimmermann unsigned int pfn_base; 313*d339386cSThomas Zimmermann unsigned int i, num_pages; 314*d339386cSThomas Zimmermann uint32_t pte; 315*d339386cSThomas Zimmermann 316*d339386cSThomas Zimmermann pfn_base = pdev->stolen_base >> PAGE_SHIFT; 317*d339386cSThomas Zimmermann num_pages = pdev->vram_stolen_size >> PAGE_SHIFT; 318*d339386cSThomas Zimmermann 319*d339386cSThomas Zimmermann drm_dbg(dev, "Set up %u stolen pages starting at 0x%08x, GTT offset %dK\n", 320*d339386cSThomas Zimmermann num_pages, pfn_base << PAGE_SHIFT, 0); 321*d339386cSThomas Zimmermann 322*d339386cSThomas Zimmermann for (i = 0; i < num_pages; ++i) { 323*d339386cSThomas Zimmermann pte = psb_gtt_mask_pte(pfn_base + i, PSB_MMU_CACHED_MEMORY); 324*d339386cSThomas Zimmermann iowrite32(pte, pdev->gtt_map + i); 325*d339386cSThomas Zimmermann } 326*d339386cSThomas Zimmermann 327*d339386cSThomas Zimmermann (void)ioread32(pdev->gtt_map + i - 1); 328*d339386cSThomas Zimmermann } 329*d339386cSThomas Zimmermann 330*d339386cSThomas Zimmermann int psb_gem_mm_init(struct drm_device *dev) 331*d339386cSThomas Zimmermann { 332*d339386cSThomas Zimmermann struct drm_psb_private *dev_priv = to_drm_psb_private(dev); 333*d339386cSThomas Zimmermann struct pci_dev *pdev = to_pci_dev(dev->dev); 334*d339386cSThomas Zimmermann unsigned long stolen_size, vram_stolen_size; 335*d339386cSThomas Zimmermann struct psb_gtt *pg; 336*d339386cSThomas Zimmermann int ret; 337*d339386cSThomas Zimmermann 338*d339386cSThomas Zimmermann mutex_init(&dev_priv->mmap_mutex); 339*d339386cSThomas Zimmermann 340*d339386cSThomas Zimmermann pg = &dev_priv->gtt; 341*d339386cSThomas Zimmermann 342*d339386cSThomas Zimmermann pci_read_config_dword(pdev, PSB_BSM, &dev_priv->stolen_base); 343*d339386cSThomas Zimmermann vram_stolen_size = pg->gtt_phys_start - dev_priv->stolen_base - PAGE_SIZE; 344*d339386cSThomas Zimmermann 345*d339386cSThomas Zimmermann stolen_size = vram_stolen_size; 346*d339386cSThomas Zimmermann 347*d339386cSThomas Zimmermann dev_dbg(dev->dev, "Stolen memory base 0x%x, size %luK\n", 348*d339386cSThomas Zimmermann dev_priv->stolen_base, vram_stolen_size / 1024); 349*d339386cSThomas Zimmermann 350*d339386cSThomas Zimmermann pg->stolen_size = stolen_size; 351*d339386cSThomas Zimmermann dev_priv->vram_stolen_size = vram_stolen_size; 352*d339386cSThomas Zimmermann 353*d339386cSThomas Zimmermann dev_priv->vram_addr = ioremap_wc(dev_priv->stolen_base, stolen_size); 354*d339386cSThomas Zimmermann if (!dev_priv->vram_addr) { 355*d339386cSThomas Zimmermann dev_err(dev->dev, "Failure to map stolen base.\n"); 356*d339386cSThomas Zimmermann ret = -ENOMEM; 357*d339386cSThomas Zimmermann goto err_mutex_destroy; 358*d339386cSThomas Zimmermann } 359*d339386cSThomas Zimmermann 360*d339386cSThomas Zimmermann psb_gem_mm_populate_stolen(dev_priv); 361*d339386cSThomas Zimmermann 362*d339386cSThomas Zimmermann return 0; 363*d339386cSThomas Zimmermann 364*d339386cSThomas Zimmermann err_mutex_destroy: 365*d339386cSThomas Zimmermann mutex_destroy(&dev_priv->mmap_mutex); 366*d339386cSThomas Zimmermann return ret; 367*d339386cSThomas Zimmermann } 368*d339386cSThomas Zimmermann 369*d339386cSThomas Zimmermann void psb_gem_mm_fini(struct drm_device *dev) 370*d339386cSThomas Zimmermann { 371*d339386cSThomas Zimmermann struct drm_psb_private *dev_priv = to_drm_psb_private(dev); 372*d339386cSThomas Zimmermann 373*d339386cSThomas Zimmermann iounmap(dev_priv->vram_addr); 374*d339386cSThomas Zimmermann 375*d339386cSThomas Zimmermann mutex_destroy(&dev_priv->mmap_mutex); 376*d339386cSThomas Zimmermann } 377*d339386cSThomas Zimmermann 378*d339386cSThomas Zimmermann /* Re-insert all pinned GEM objects into GTT. */ 379*d339386cSThomas Zimmermann static void psb_gem_mm_populate_resources(struct drm_psb_private *pdev) 380*d339386cSThomas Zimmermann { 381*d339386cSThomas Zimmermann unsigned int restored = 0, total = 0, size = 0; 382*d339386cSThomas Zimmermann struct resource *r = pdev->gtt_mem->child; 383*d339386cSThomas Zimmermann struct drm_device *dev = &pdev->dev; 384*d339386cSThomas Zimmermann struct psb_gem_object *pobj; 385*d339386cSThomas Zimmermann 386*d339386cSThomas Zimmermann while (r) { 387*d339386cSThomas Zimmermann /* 388*d339386cSThomas Zimmermann * TODO: GTT restoration needs a refactoring, so that we don't have to touch 389*d339386cSThomas Zimmermann * struct psb_gem_object here. The type represents a GEM object and is 390*d339386cSThomas Zimmermann * not related to the GTT itself. 391*d339386cSThomas Zimmermann */ 392*d339386cSThomas Zimmermann pobj = container_of(r, struct psb_gem_object, resource); 393*d339386cSThomas Zimmermann if (pobj->pages) { 394*d339386cSThomas Zimmermann psb_gtt_insert_pages(pdev, &pobj->resource, pobj->pages); 395*d339386cSThomas Zimmermann size += resource_size(&pobj->resource); 396*d339386cSThomas Zimmermann ++restored; 397*d339386cSThomas Zimmermann } 398*d339386cSThomas Zimmermann r = r->sibling; 399*d339386cSThomas Zimmermann ++total; 400*d339386cSThomas Zimmermann } 401*d339386cSThomas Zimmermann 402*d339386cSThomas Zimmermann drm_dbg(dev, "Restored %u of %u gtt ranges (%u KB)", restored, total, (size / 1024)); 403*d339386cSThomas Zimmermann } 404*d339386cSThomas Zimmermann 405*d339386cSThomas Zimmermann int psb_gem_mm_resume(struct drm_device *dev) 406*d339386cSThomas Zimmermann { 407*d339386cSThomas Zimmermann struct drm_psb_private *dev_priv = to_drm_psb_private(dev); 408*d339386cSThomas Zimmermann struct pci_dev *pdev = to_pci_dev(dev->dev); 409*d339386cSThomas Zimmermann unsigned long stolen_size, vram_stolen_size; 410*d339386cSThomas Zimmermann struct psb_gtt *pg; 411*d339386cSThomas Zimmermann 412*d339386cSThomas Zimmermann pg = &dev_priv->gtt; 413*d339386cSThomas Zimmermann 414*d339386cSThomas Zimmermann pci_read_config_dword(pdev, PSB_BSM, &dev_priv->stolen_base); 415*d339386cSThomas Zimmermann vram_stolen_size = pg->gtt_phys_start - dev_priv->stolen_base - PAGE_SIZE; 416*d339386cSThomas Zimmermann 417*d339386cSThomas Zimmermann stolen_size = vram_stolen_size; 418*d339386cSThomas Zimmermann 419*d339386cSThomas Zimmermann dev_dbg(dev->dev, "Stolen memory base 0x%x, size %luK\n", dev_priv->stolen_base, 420*d339386cSThomas Zimmermann vram_stolen_size / 1024); 421*d339386cSThomas Zimmermann 422*d339386cSThomas Zimmermann if (stolen_size != pg->stolen_size) { 423*d339386cSThomas Zimmermann dev_err(dev->dev, "GTT resume error.\n"); 424*d339386cSThomas Zimmermann return -EINVAL; 425*d339386cSThomas Zimmermann } 426*d339386cSThomas Zimmermann 427*d339386cSThomas Zimmermann psb_gem_mm_populate_stolen(dev_priv); 428*d339386cSThomas Zimmermann psb_gem_mm_populate_resources(dev_priv); 429*d339386cSThomas Zimmermann 430*d339386cSThomas Zimmermann return 0; 431*d339386cSThomas Zimmermann } 432