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:
Dave Airlie 2006-03-19 18:56:12 +11:00
parent 60a6dc55b9
commit ddf19b973b
4 changed files with 44 additions and 23 deletions

View File

@ -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
*/ */

View File

@ -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;

View File

@ -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,

View File

@ -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,7 +142,13 @@ 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? */
/* 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); dmah->busaddr);
} }