Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+44 -23
+7 -7
drivers/char/drm/drmP.h
··· 357 357 spinlock_t lock; 358 358 } drm_freelist_t; 359 359 360 + typedef struct drm_dma_handle { 361 + dma_addr_t busaddr; 362 + void *vaddr; 363 + size_t size; 364 + } drm_dma_handle_t; 365 + 360 366 /** 361 367 * Buffer entry. There is one of this for each buffer size order. 362 368 */ ··· 372 366 drm_buf_t *buflist; /**< buffer list */ 373 367 int seg_count; 374 368 int page_order; 375 - unsigned long *seglist; 369 + drm_dma_handle_t **seglist; 376 370 377 371 drm_freelist_t freelist; 378 372 } drm_buf_entry_t; ··· 488 482 int context; 489 483 drm_hw_lock_t *lock; 490 484 } drm_sigdata_t; 491 - 492 - typedef struct drm_dma_handle { 493 - dma_addr_t busaddr; 494 - void *vaddr; 495 - size_t size; 496 - } drm_dma_handle_t; 497 485 498 486 /** 499 487 * Mappings list
+11 -9
drivers/char/drm/drm_bufs.c
··· 474 474 if (entry->seg_count) { 475 475 for (i = 0; i < entry->seg_count; i++) { 476 476 if (entry->seglist[i]) { 477 - drm_free_pages(entry->seglist[i], 478 - entry->page_order, DRM_MEM_DMA); 477 + drm_pci_free(dev, entry->seglist[i]); 479 478 } 480 479 } 481 480 drm_free(entry->seglist, ··· 677 678 int total; 678 679 int page_order; 679 680 drm_buf_entry_t *entry; 680 - unsigned long page; 681 + drm_dma_handle_t *dmah; 681 682 drm_buf_t *buf; 682 683 int alignment; 683 684 unsigned long offset; ··· 780 781 page_count = 0; 781 782 782 783 while (entry->buf_count < count) { 783 - page = drm_alloc_pages(page_order, DRM_MEM_DMA); 784 - if (!page) { 784 + 785 + dmah = drm_pci_alloc(dev, PAGE_SIZE << page_order, 0x1000, 0xfffffffful); 786 + 787 + if (!dmah) { 785 788 /* Set count correctly so we free the proper amount. */ 786 789 entry->buf_count = count; 787 790 entry->seg_count = count; ··· 795 794 atomic_dec(&dev->buf_alloc); 796 795 return -ENOMEM; 797 796 } 798 - entry->seglist[entry->seg_count++] = page; 797 + entry->seglist[entry->seg_count++] = dmah; 799 798 for (i = 0; i < (1 << page_order); i++) { 800 799 DRM_DEBUG("page %d @ 0x%08lx\n", 801 800 dma->page_count + page_count, 802 - page + PAGE_SIZE * i); 801 + (unsigned long)dmah->vaddr + PAGE_SIZE * i); 803 802 temp_pagelist[dma->page_count + page_count++] 804 - = page + PAGE_SIZE * i; 803 + = (unsigned long)dmah->vaddr + PAGE_SIZE * i; 805 804 } 806 805 for (offset = 0; 807 806 offset + size <= total && entry->buf_count < count; ··· 812 811 buf->order = order; 813 812 buf->used = 0; 814 813 buf->offset = (dma->byte_count + byte_count + offset); 815 - buf->address = (void *)(page + offset); 814 + buf->address = (void *)(dmah->vaddr + offset); 815 + buf->bus_address = dmah->busaddr + offset; 816 816 buf->next = NULL; 817 817 buf->waiting = 0; 818 818 buf->pending = 0;
+1 -3
drivers/char/drm/drm_dma.c
··· 85 85 dma->bufs[i].seg_count); 86 86 for (j = 0; j < dma->bufs[i].seg_count; j++) { 87 87 if (dma->bufs[i].seglist[j]) { 88 - drm_free_pages(dma->bufs[i].seglist[j], 89 - dma->bufs[i].page_order, 90 - DRM_MEM_DMA); 88 + drm_pci_free(dev, dma->bufs[i].seglist[j]); 91 89 } 92 90 } 93 91 drm_free(dma->bufs[i].seglist,
+25 -4
drivers/char/drm/drm_pci.c
··· 50 50 dma_addr_t maxaddr) 51 51 { 52 52 drm_dma_handle_t *dmah; 53 + #if 1 54 + unsigned long addr; 55 + size_t sz; 56 + #endif 53 57 #ifdef DRM_DEBUG_MEMORY 54 58 int area = DRM_MEM_DMA; 55 59 ··· 83 79 return NULL; 84 80 85 81 dmah->size = size; 86 - dmah->vaddr = pci_alloc_consistent(dev->pdev, size, &dmah->busaddr); 82 + dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, GFP_KERNEL | __GFP_COMP); 87 83 88 84 #ifdef DRM_DEBUG_MEMORY 89 85 if (dmah->vaddr == NULL) { ··· 108 104 109 105 memset(dmah->vaddr, 0, size); 110 106 107 + /* XXX - Is virt_to_page() legal for consistent mem? */ 108 + /* Reserve */ 109 + for (addr = (unsigned long)dmah->vaddr, sz = size; 110 + sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { 111 + SetPageReserved(virt_to_page(addr)); 112 + } 113 + 111 114 return dmah; 112 115 } 113 116 114 117 EXPORT_SYMBOL(drm_pci_alloc); 115 118 116 119 /** 117 - * \brief Free a PCI consistent memory block with freeing its descriptor. 120 + * \brief Free a PCI consistent memory block without freeing its descriptor. 118 121 * 119 122 * This function is for internal use in the Linux-specific DRM core code. 120 123 */ 121 124 void __drm_pci_free(drm_device_t * dev, drm_dma_handle_t * dmah) 122 125 { 126 + #if 1 127 + unsigned long addr; 128 + size_t sz; 129 + #endif 123 130 #ifdef DRM_DEBUG_MEMORY 124 131 int area = DRM_MEM_DMA; 125 132 int alloc_count; ··· 142 127 DRM_MEM_ERROR(area, "Attempt to free address 0\n"); 143 128 #endif 144 129 } else { 145 - pci_free_consistent(dev->pdev, dmah->size, dmah->vaddr, 146 - dmah->busaddr); 130 + /* XXX - Is virt_to_page() legal for consistent mem? */ 131 + /* Unreserve */ 132 + for (addr = (unsigned long)dmah->vaddr, sz = dmah->size; 133 + sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { 134 + ClearPageReserved(virt_to_page(addr)); 135 + } 136 + dma_free_coherent(&dev->pdev->dev, dmah->size, dmah->vaddr, 137 + dmah->busaddr); 147 138 } 148 139 149 140 #ifdef DRM_DEBUG_MEMORY