mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	drm: fixup PCI DMA support
This patch makes the PCI support use the correct Linux interfaces finally. Tested in DRM CVS on PCI MGA card. Signed-off-by: Dave Airlie <airlied@linux.ie>
This commit is contained in:
		
							parent
							
								
									60a6dc55b9
								
							
						
					
					
						commit
						ddf19b973b
					
				
					 4 changed files with 44 additions and 23 deletions
				
			
		|  | @ -357,6 +357,12 @@ typedef struct drm_freelist { | ||||||
| 	spinlock_t lock; | 	spinlock_t lock; | ||||||
| } drm_freelist_t; | } drm_freelist_t; | ||||||
| 
 | 
 | ||||||
|  | typedef struct drm_dma_handle { | ||||||
|  | 	dma_addr_t busaddr; | ||||||
|  | 	void *vaddr; | ||||||
|  | 	size_t size; | ||||||
|  | } drm_dma_handle_t; | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Buffer entry.  There is one of this for each buffer size order. |  * Buffer entry.  There is one of this for each buffer size order. | ||||||
|  */ |  */ | ||||||
|  | @ -366,7 +372,7 @@ typedef struct drm_buf_entry { | ||||||
| 	drm_buf_t *buflist;		/**< buffer list */ | 	drm_buf_t *buflist;		/**< buffer list */ | ||||||
| 	int seg_count; | 	int seg_count; | ||||||
| 	int page_order; | 	int page_order; | ||||||
| 	unsigned long *seglist; | 	drm_dma_handle_t **seglist; | ||||||
| 
 | 
 | ||||||
| 	drm_freelist_t freelist; | 	drm_freelist_t freelist; | ||||||
| } drm_buf_entry_t; | } drm_buf_entry_t; | ||||||
|  | @ -483,12 +489,6 @@ typedef struct drm_sigdata { | ||||||
| 	drm_hw_lock_t *lock; | 	drm_hw_lock_t *lock; | ||||||
| } drm_sigdata_t; | } drm_sigdata_t; | ||||||
| 
 | 
 | ||||||
| typedef struct drm_dma_handle { |  | ||||||
| 	dma_addr_t busaddr; |  | ||||||
| 	void *vaddr; |  | ||||||
| 	size_t size; |  | ||||||
| } drm_dma_handle_t; |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * Mappings list |  * Mappings list | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | @ -474,8 +474,7 @@ static void drm_cleanup_buf_error(drm_device_t * dev, drm_buf_entry_t * entry) | ||||||
| 	if (entry->seg_count) { | 	if (entry->seg_count) { | ||||||
| 		for (i = 0; i < entry->seg_count; i++) { | 		for (i = 0; i < entry->seg_count; i++) { | ||||||
| 			if (entry->seglist[i]) { | 			if (entry->seglist[i]) { | ||||||
| 				drm_free_pages(entry->seglist[i], | 				drm_pci_free(dev, entry->seglist[i]); | ||||||
| 					       entry->page_order, DRM_MEM_DMA); |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		drm_free(entry->seglist, | 		drm_free(entry->seglist, | ||||||
|  | @ -678,7 +677,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) | ||||||
| 	int total; | 	int total; | ||||||
| 	int page_order; | 	int page_order; | ||||||
| 	drm_buf_entry_t *entry; | 	drm_buf_entry_t *entry; | ||||||
| 	unsigned long page; | 	drm_dma_handle_t *dmah; | ||||||
| 	drm_buf_t *buf; | 	drm_buf_t *buf; | ||||||
| 	int alignment; | 	int alignment; | ||||||
| 	unsigned long offset; | 	unsigned long offset; | ||||||
|  | @ -781,8 +780,10 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) | ||||||
| 	page_count = 0; | 	page_count = 0; | ||||||
| 
 | 
 | ||||||
| 	while (entry->buf_count < count) { | 	while (entry->buf_count < count) { | ||||||
| 		page = drm_alloc_pages(page_order, DRM_MEM_DMA); | 		 | ||||||
| 		if (!page) { | 		dmah = drm_pci_alloc(dev, PAGE_SIZE << page_order, 0x1000, 0xfffffffful); | ||||||
|  | 		 | ||||||
|  | 		if (!dmah) { | ||||||
| 			/* Set count correctly so we free the proper amount. */ | 			/* Set count correctly so we free the proper amount. */ | ||||||
| 			entry->buf_count = count; | 			entry->buf_count = count; | ||||||
| 			entry->seg_count = count; | 			entry->seg_count = count; | ||||||
|  | @ -794,13 +795,13 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) | ||||||
| 			atomic_dec(&dev->buf_alloc); | 			atomic_dec(&dev->buf_alloc); | ||||||
| 			return -ENOMEM; | 			return -ENOMEM; | ||||||
| 		} | 		} | ||||||
| 		entry->seglist[entry->seg_count++] = page; | 		entry->seglist[entry->seg_count++] = dmah; | ||||||
| 		for (i = 0; i < (1 << page_order); i++) { | 		for (i = 0; i < (1 << page_order); i++) { | ||||||
| 			DRM_DEBUG("page %d @ 0x%08lx\n", | 			DRM_DEBUG("page %d @ 0x%08lx\n", | ||||||
| 				  dma->page_count + page_count, | 				  dma->page_count + page_count, | ||||||
| 				  page + PAGE_SIZE * i); | 				  (unsigned long)dmah->vaddr + PAGE_SIZE * i); | ||||||
| 			temp_pagelist[dma->page_count + page_count++] | 			temp_pagelist[dma->page_count + page_count++] | ||||||
| 			    = page + PAGE_SIZE * i; | 				= (unsigned long)dmah->vaddr + PAGE_SIZE * i; | ||||||
| 		} | 		} | ||||||
| 		for (offset = 0; | 		for (offset = 0; | ||||||
| 		     offset + size <= total && entry->buf_count < count; | 		     offset + size <= total && entry->buf_count < count; | ||||||
|  | @ -811,7 +812,8 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) | ||||||
| 			buf->order = order; | 			buf->order = order; | ||||||
| 			buf->used = 0; | 			buf->used = 0; | ||||||
| 			buf->offset = (dma->byte_count + byte_count + offset); | 			buf->offset = (dma->byte_count + byte_count + offset); | ||||||
| 			buf->address = (void *)(page + offset); | 			buf->address = (void *)(dmah->vaddr + offset); | ||||||
|  | 			buf->bus_address = dmah->busaddr + offset; | ||||||
| 			buf->next = NULL; | 			buf->next = NULL; | ||||||
| 			buf->waiting = 0; | 			buf->waiting = 0; | ||||||
| 			buf->pending = 0; | 			buf->pending = 0; | ||||||
|  |  | ||||||
|  | @ -85,9 +85,7 @@ void drm_dma_takedown(drm_device_t * dev) | ||||||
| 				  dma->bufs[i].seg_count); | 				  dma->bufs[i].seg_count); | ||||||
| 			for (j = 0; j < dma->bufs[i].seg_count; j++) { | 			for (j = 0; j < dma->bufs[i].seg_count; j++) { | ||||||
| 				if (dma->bufs[i].seglist[j]) { | 				if (dma->bufs[i].seglist[j]) { | ||||||
| 					drm_free_pages(dma->bufs[i].seglist[j], | 					drm_pci_free(dev, dma->bufs[i].seglist[j]); | ||||||
| 						       dma->bufs[i].page_order, |  | ||||||
| 						       DRM_MEM_DMA); |  | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			drm_free(dma->bufs[i].seglist, | 			drm_free(dma->bufs[i].seglist, | ||||||
|  |  | ||||||
|  | @ -50,6 +50,10 @@ drm_dma_handle_t *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align, | ||||||
| 				dma_addr_t maxaddr) | 				dma_addr_t maxaddr) | ||||||
| { | { | ||||||
| 	drm_dma_handle_t *dmah; | 	drm_dma_handle_t *dmah; | ||||||
|  | #if 1 | ||||||
|  | 	unsigned long addr; | ||||||
|  | 	size_t sz; | ||||||
|  | #endif | ||||||
| #ifdef DRM_DEBUG_MEMORY | #ifdef DRM_DEBUG_MEMORY | ||||||
| 	int area = DRM_MEM_DMA; | 	int area = DRM_MEM_DMA; | ||||||
| 
 | 
 | ||||||
|  | @ -79,7 +83,7 @@ drm_dma_handle_t *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align, | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 
 | 
 | ||||||
| 	dmah->size = size; | 	dmah->size = size; | ||||||
| 	dmah->vaddr = pci_alloc_consistent(dev->pdev, size, &dmah->busaddr); | 	dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, GFP_KERNEL | __GFP_COMP); | ||||||
| 
 | 
 | ||||||
| #ifdef DRM_DEBUG_MEMORY | #ifdef DRM_DEBUG_MEMORY | ||||||
| 	if (dmah->vaddr == NULL) { | 	if (dmah->vaddr == NULL) { | ||||||
|  | @ -104,18 +108,29 @@ drm_dma_handle_t *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align, | ||||||
| 
 | 
 | ||||||
| 	memset(dmah->vaddr, 0, size); | 	memset(dmah->vaddr, 0, size); | ||||||
| 
 | 
 | ||||||
|  | 	/* XXX - Is virt_to_page() legal for consistent mem? */ | ||||||
|  | 	/* Reserve */ | ||||||
|  | 	for (addr = (unsigned long)dmah->vaddr, sz = size; | ||||||
|  | 	     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { | ||||||
|  | 		SetPageReserved(virt_to_page(addr)); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return dmah; | 	return dmah; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| EXPORT_SYMBOL(drm_pci_alloc); | EXPORT_SYMBOL(drm_pci_alloc); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * \brief Free a PCI consistent memory block with freeing its descriptor. |  * \brief Free a PCI consistent memory block without freeing its descriptor. | ||||||
|  * |  * | ||||||
|  * This function is for internal use in the Linux-specific DRM core code. |  * This function is for internal use in the Linux-specific DRM core code. | ||||||
|  */ |  */ | ||||||
| void __drm_pci_free(drm_device_t * dev, drm_dma_handle_t * dmah) | void __drm_pci_free(drm_device_t * dev, drm_dma_handle_t * dmah) | ||||||
| { | { | ||||||
|  | #if 1 | ||||||
|  | 	unsigned long addr; | ||||||
|  | 	size_t sz; | ||||||
|  | #endif | ||||||
| #ifdef DRM_DEBUG_MEMORY | #ifdef DRM_DEBUG_MEMORY | ||||||
| 	int area = DRM_MEM_DMA; | 	int area = DRM_MEM_DMA; | ||||||
| 	int alloc_count; | 	int alloc_count; | ||||||
|  | @ -127,8 +142,14 @@ void __drm_pci_free(drm_device_t * dev, drm_dma_handle_t * dmah) | ||||||
| 		DRM_MEM_ERROR(area, "Attempt to free address 0\n"); | 		DRM_MEM_ERROR(area, "Attempt to free address 0\n"); | ||||||
| #endif | #endif | ||||||
| 	} else { | 	} else { | ||||||
| 		pci_free_consistent(dev->pdev, dmah->size, dmah->vaddr, | 		/* XXX - Is virt_to_page() legal for consistent mem? */ | ||||||
| 				    dmah->busaddr); | 		/* Unreserve */ | ||||||
|  | 		for (addr = (unsigned long)dmah->vaddr, sz = dmah->size; | ||||||
|  | 		     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { | ||||||
|  | 			ClearPageReserved(virt_to_page(addr)); | ||||||
|  | 		} | ||||||
|  | 		dma_free_coherent(&dev->pdev->dev, dmah->size, dmah->vaddr, | ||||||
|  | 				  dmah->busaddr); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| #ifdef DRM_DEBUG_MEMORY | #ifdef DRM_DEBUG_MEMORY | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Dave Airlie
						Dave Airlie