diff options
Diffstat (limited to 'drivers/gpu/drm/gma500/gem.c')
| -rw-r--r-- | drivers/gpu/drm/gma500/gem.c | 161 | 
1 files changed, 150 insertions, 11 deletions
diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c index 8d65af80bb08..dffe37490206 100644 --- a/drivers/gpu/drm/gma500/gem.c +++ b/drivers/gpu/drm/gma500/gem.c @@ -21,6 +21,10 @@  #include "gem.h"  #include "psb_drv.h" +/* + * PSB GEM object + */ +  int psb_gem_pin(struct psb_gem_object *pobj)  {  	struct drm_gem_object *obj = &pobj->base; @@ -31,7 +35,9 @@ int psb_gem_pin(struct psb_gem_object *pobj)  	unsigned int npages;  	int ret; -	mutex_lock(&dev_priv->gtt_mutex); +	ret = dma_resv_lock(obj->resv, NULL); +	if (drm_WARN_ONCE(dev, ret, "dma_resv_lock() failed, ret=%d\n", ret)) +		return ret;  	if (pobj->in_gart || pobj->stolen)  		goto out; /* already mapped */ @@ -39,7 +45,7 @@ int psb_gem_pin(struct psb_gem_object *pobj)  	pages = drm_gem_get_pages(obj);  	if (IS_ERR(pages)) {  		ret = PTR_ERR(pages); -		goto err_mutex_unlock; +		goto err_dma_resv_unlock;  	}  	npages = obj->size / PAGE_SIZE; @@ -51,17 +57,16 @@ int psb_gem_pin(struct psb_gem_object *pobj)  			     (gpu_base + pobj->offset), npages, 0, 0,  			     PSB_MMU_CACHED_MEMORY); -	pobj->npage = npages;  	pobj->pages = pages;  out:  	++pobj->in_gart; -	mutex_unlock(&dev_priv->gtt_mutex); +	dma_resv_unlock(obj->resv);  	return 0; -err_mutex_unlock: -	mutex_unlock(&dev_priv->gtt_mutex); +err_dma_resv_unlock: +	dma_resv_unlock(obj->resv);  	return ret;  } @@ -71,8 +76,12 @@ void psb_gem_unpin(struct psb_gem_object *pobj)  	struct drm_device *dev = obj->dev;  	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);  	u32 gpu_base = dev_priv->gtt.gatt_start; +	unsigned long npages; +	int ret; -	mutex_lock(&dev_priv->gtt_mutex); +	ret = dma_resv_lock(obj->resv, NULL); +	if (drm_WARN_ONCE(dev, ret, "dma_resv_lock() failed, ret=%d\n", ret)) +		return;  	WARN_ON(!pobj->in_gart); @@ -81,19 +90,20 @@ void psb_gem_unpin(struct psb_gem_object *pobj)  	if (pobj->in_gart || pobj->stolen)  		goto out; +	npages = obj->size / PAGE_SIZE; +  	psb_mmu_remove_pages(psb_mmu_get_default_pd(dev_priv->mmu), -			     (gpu_base + pobj->offset), pobj->npage, 0, 0); +			     (gpu_base + pobj->offset), npages, 0, 0);  	psb_gtt_remove_pages(dev_priv, &pobj->resource);  	/* Reset caching flags */ -	set_pages_array_wb(pobj->pages, pobj->npage); +	set_pages_array_wb(pobj->pages, npages);  	drm_gem_put_pages(obj, pobj->pages, true, false);  	pobj->pages = NULL; -	pobj->npage = 0;  out: -	mutex_unlock(&dev_priv->gtt_mutex); +	dma_resv_unlock(obj->resv);  }  static vm_fault_t psb_gem_fault(struct vm_fault *vmf); @@ -290,3 +300,132 @@ fail:  	return ret;  } + +/* + * Memory management + */ + +/* Insert vram stolen pages into the GTT. */ +static void psb_gem_mm_populate_stolen(struct drm_psb_private *pdev) +{ +	struct drm_device *dev = &pdev->dev; +	unsigned int pfn_base; +	unsigned int i, num_pages; +	uint32_t pte; + +	pfn_base = pdev->stolen_base >> PAGE_SHIFT; +	num_pages = pdev->vram_stolen_size >> PAGE_SHIFT; + +	drm_dbg(dev, "Set up %u stolen pages starting at 0x%08x, GTT offset %dK\n", +		num_pages, pfn_base << PAGE_SHIFT, 0); + +	for (i = 0; i < num_pages; ++i) { +		pte = psb_gtt_mask_pte(pfn_base + i, PSB_MMU_CACHED_MEMORY); +		iowrite32(pte, pdev->gtt_map + i); +	} + +	(void)ioread32(pdev->gtt_map + i - 1); +} + +int psb_gem_mm_init(struct drm_device *dev) +{ +	struct drm_psb_private *dev_priv = to_drm_psb_private(dev); +	struct pci_dev *pdev = to_pci_dev(dev->dev); +	unsigned long stolen_size, vram_stolen_size; +	struct psb_gtt *pg; +	int ret; + +	mutex_init(&dev_priv->mmap_mutex); + +	pg = &dev_priv->gtt; + +	pci_read_config_dword(pdev, PSB_BSM, &dev_priv->stolen_base); +	vram_stolen_size = pg->gtt_phys_start - dev_priv->stolen_base - PAGE_SIZE; + +	stolen_size = vram_stolen_size; + +	dev_dbg(dev->dev, "Stolen memory base 0x%x, size %luK\n", +		dev_priv->stolen_base, vram_stolen_size / 1024); + +	pg->stolen_size = stolen_size; +	dev_priv->vram_stolen_size = vram_stolen_size; + +	dev_priv->vram_addr = ioremap_wc(dev_priv->stolen_base, stolen_size); +	if (!dev_priv->vram_addr) { +		dev_err(dev->dev, "Failure to map stolen base.\n"); +		ret = -ENOMEM; +		goto err_mutex_destroy; +	} + +	psb_gem_mm_populate_stolen(dev_priv); + +	return 0; + +err_mutex_destroy: +	mutex_destroy(&dev_priv->mmap_mutex); +	return ret; +} + +void psb_gem_mm_fini(struct drm_device *dev) +{ +	struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + +	iounmap(dev_priv->vram_addr); + +	mutex_destroy(&dev_priv->mmap_mutex); +} + +/* Re-insert all pinned GEM objects into GTT. */ +static void psb_gem_mm_populate_resources(struct drm_psb_private *pdev) +{ +	unsigned int restored = 0, total = 0, size = 0; +	struct resource *r = pdev->gtt_mem->child; +	struct drm_device *dev = &pdev->dev; +	struct psb_gem_object *pobj; + +	while (r) { +		/* +		 * TODO: GTT restoration needs a refactoring, so that we don't have to touch +		 *       struct psb_gem_object here. The type represents a GEM object and is +		 *       not related to the GTT itself. +		 */ +		pobj = container_of(r, struct psb_gem_object, resource); +		if (pobj->pages) { +			psb_gtt_insert_pages(pdev, &pobj->resource, pobj->pages); +			size += resource_size(&pobj->resource); +			++restored; +		} +		r = r->sibling; +		++total; +	} + +	drm_dbg(dev, "Restored %u of %u gtt ranges (%u KB)", restored, total, (size / 1024)); +} + +int psb_gem_mm_resume(struct drm_device *dev) +{ +	struct drm_psb_private *dev_priv = to_drm_psb_private(dev); +	struct pci_dev *pdev = to_pci_dev(dev->dev); +	unsigned long stolen_size, vram_stolen_size; +	struct psb_gtt *pg; + +	pg = &dev_priv->gtt; + +	pci_read_config_dword(pdev, PSB_BSM, &dev_priv->stolen_base); +	vram_stolen_size = pg->gtt_phys_start - dev_priv->stolen_base - PAGE_SIZE; + +	stolen_size = vram_stolen_size; + +	dev_dbg(dev->dev, "Stolen memory base 0x%x, size %luK\n", dev_priv->stolen_base, +		vram_stolen_size / 1024); + +	if (stolen_size != pg->stolen_size) { +		dev_err(dev->dev, "GTT resume error.\n"); +		return -EINVAL; +	} + +	psb_gem_mm_populate_stolen(dev_priv); +	psb_gem_mm_populate_resources(dev_priv); + +	return 0; +}  |