diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c')
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c | 179 | 
1 files changed, 15 insertions, 164 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c index 1a0bf07fe54..61d8d803199 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c @@ -32,9 +32,11 @@  #define VMW_PPN_SIZE (sizeof(unsigned long))  /* A future safe maximum remap size. */  #define VMW_PPN_PER_REMAP ((31 * 1024) / VMW_PPN_SIZE) +#define DMA_ADDR_INVALID ((dma_addr_t) 0) +#define DMA_PAGE_INVALID 0UL  static int vmw_gmr2_bind(struct vmw_private *dev_priv, -			 struct page *pages[], +			 struct vmw_piter *iter,  			 unsigned long num_pages,  			 int gmr_id)  { @@ -81,11 +83,13 @@ static int vmw_gmr2_bind(struct vmw_private *dev_priv,  		for (i = 0; i < nr; ++i) {  			if (VMW_PPN_SIZE <= 4) -				*cmd = page_to_pfn(*pages++); +				*cmd = vmw_piter_dma_addr(iter) >> PAGE_SHIFT;  			else -				*((uint64_t *)cmd) = page_to_pfn(*pages++); +				*((uint64_t *)cmd) = vmw_piter_dma_addr(iter) >> +					PAGE_SHIFT;  			cmd += VMW_PPN_SIZE / sizeof(*cmd); +			vmw_piter_next(iter);  		}  		num_pages -= nr; @@ -120,181 +124,28 @@ static void vmw_gmr2_unbind(struct vmw_private *dev_priv,  	vmw_fifo_commit(dev_priv, define_size);  } -/** - * FIXME: Adjust to the ttm lowmem / highmem storage to minimize - * the number of used descriptors. - */ - -static int vmw_gmr_build_descriptors(struct list_head *desc_pages, -				     struct page *pages[], -				     unsigned long num_pages) -{ -	struct page *page, *next; -	struct svga_guest_mem_descriptor *page_virtual = NULL; -	struct svga_guest_mem_descriptor *desc_virtual = NULL; -	unsigned int desc_per_page; -	unsigned long prev_pfn; -	unsigned long pfn; -	int ret; - -	desc_per_page = PAGE_SIZE / -	    sizeof(struct svga_guest_mem_descriptor) - 1; - -	while (likely(num_pages != 0)) { -		page = alloc_page(__GFP_HIGHMEM); -		if (unlikely(page == NULL)) { -			ret = -ENOMEM; -			goto out_err; -		} - -		list_add_tail(&page->lru, desc_pages); - -		/* -		 * Point previous page terminating descriptor to this -		 * page before unmapping it. -		 */ - -		if (likely(page_virtual != NULL)) { -			desc_virtual->ppn = page_to_pfn(page); -			kunmap_atomic(page_virtual); -		} - -		page_virtual = kmap_atomic(page); -		desc_virtual = page_virtual - 1; -		prev_pfn = ~(0UL); - -		while (likely(num_pages != 0)) { -			pfn = page_to_pfn(*pages); - -			if (pfn != prev_pfn + 1) { - -				if (desc_virtual - page_virtual == -				    desc_per_page - 1) -					break; - -				(++desc_virtual)->ppn = cpu_to_le32(pfn); -				desc_virtual->num_pages = cpu_to_le32(1); -			} else { -				uint32_t tmp = -				    le32_to_cpu(desc_virtual->num_pages); -				desc_virtual->num_pages = cpu_to_le32(tmp + 1); -			} -			prev_pfn = pfn; -			--num_pages; -			++pages; -		} - -		(++desc_virtual)->ppn = cpu_to_le32(0); -		desc_virtual->num_pages = cpu_to_le32(0); -	} - -	if (likely(page_virtual != NULL)) -		kunmap_atomic(page_virtual); - -	return 0; -out_err: -	list_for_each_entry_safe(page, next, desc_pages, lru) { -		list_del_init(&page->lru); -		__free_page(page); -	} -	return ret; -} - -static inline void vmw_gmr_free_descriptors(struct list_head *desc_pages) -{ -	struct page *page, *next; - -	list_for_each_entry_safe(page, next, desc_pages, lru) { -		list_del_init(&page->lru); -		__free_page(page); -	} -} - -static void vmw_gmr_fire_descriptors(struct vmw_private *dev_priv, -				     int gmr_id, struct list_head *desc_pages) -{ -	struct page *page; - -	if (unlikely(list_empty(desc_pages))) -		return; - -	page = list_entry(desc_pages->next, struct page, lru); - -	mutex_lock(&dev_priv->hw_mutex); - -	vmw_write(dev_priv, SVGA_REG_GMR_ID, gmr_id); -	wmb(); -	vmw_write(dev_priv, SVGA_REG_GMR_DESCRIPTOR, page_to_pfn(page)); -	mb(); - -	mutex_unlock(&dev_priv->hw_mutex); - -} - -/** - * FIXME: Adjust to the ttm lowmem / highmem storage to minimize - * the number of used descriptors. - */ - -static unsigned long vmw_gmr_count_descriptors(struct page *pages[], -					unsigned long num_pages) -{ -	unsigned long prev_pfn = ~(0UL); -	unsigned long pfn; -	unsigned long descriptors = 0; - -	while (num_pages--) { -		pfn = page_to_pfn(*pages++); -		if (prev_pfn + 1 != pfn) -			++descriptors; -		prev_pfn = pfn; -	} - -	return descriptors; -}  int vmw_gmr_bind(struct vmw_private *dev_priv, -		 struct page *pages[], +		 const struct vmw_sg_table *vsgt,  		 unsigned long num_pages,  		 int gmr_id)  { -	struct list_head desc_pages; -	int ret; +	struct vmw_piter data_iter; -	if (likely(dev_priv->capabilities & SVGA_CAP_GMR2)) -		return vmw_gmr2_bind(dev_priv, pages, num_pages, gmr_id); +	vmw_piter_start(&data_iter, vsgt, 0); -	if (unlikely(!(dev_priv->capabilities & SVGA_CAP_GMR))) -		return -EINVAL; +	if (unlikely(!vmw_piter_next(&data_iter))) +		return 0; -	if (vmw_gmr_count_descriptors(pages, num_pages) > -	    dev_priv->max_gmr_descriptors) +	if (unlikely(!(dev_priv->capabilities & SVGA_CAP_GMR2)))  		return -EINVAL; -	INIT_LIST_HEAD(&desc_pages); - -	ret = vmw_gmr_build_descriptors(&desc_pages, pages, num_pages); -	if (unlikely(ret != 0)) -		return ret; - -	vmw_gmr_fire_descriptors(dev_priv, gmr_id, &desc_pages); -	vmw_gmr_free_descriptors(&desc_pages); - -	return 0; +	return vmw_gmr2_bind(dev_priv, &data_iter, num_pages, gmr_id);  }  void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id)  { -	if (likely(dev_priv->capabilities & SVGA_CAP_GMR2)) { +	if (likely(dev_priv->capabilities & SVGA_CAP_GMR2))  		vmw_gmr2_unbind(dev_priv, gmr_id); -		return; -	} - -	mutex_lock(&dev_priv->hw_mutex); -	vmw_write(dev_priv, SVGA_REG_GMR_ID, gmr_id); -	wmb(); -	vmw_write(dev_priv, SVGA_REG_GMR_DESCRIPTOR, 0); -	mb(); -	mutex_unlock(&dev_priv->hw_mutex);  }  | 
