Skip to content

Commit

Permalink
drm: fixup PCI DMA support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Dave Airlie committed Mar 19, 2006
1 parent 60a6dc5 commit ddf19b9
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 23 deletions.
14 changes: 7 additions & 7 deletions drivers/char/drm/drmP.h
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,12 @@ typedef struct drm_freelist {
spinlock_t lock;
} 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.
*/
Expand All @@ -366,7 +372,7 @@ typedef struct drm_buf_entry {
drm_buf_t *buflist; /**< buffer list */
int seg_count;
int page_order;
unsigned long *seglist;
drm_dma_handle_t **seglist;

drm_freelist_t freelist;
} drm_buf_entry_t;
Expand Down Expand Up @@ -483,12 +489,6 @@ typedef struct drm_sigdata {
drm_hw_lock_t *lock;
} drm_sigdata_t;

typedef struct drm_dma_handle {
dma_addr_t busaddr;
void *vaddr;
size_t size;
} drm_dma_handle_t;

/**
* Mappings list
*/
Expand Down
20 changes: 11 additions & 9 deletions drivers/char/drm/drm_bufs.c
Original file line number Diff line number Diff line change
Expand Up @@ -474,8 +474,7 @@ static void drm_cleanup_buf_error(drm_device_t * dev, drm_buf_entry_t * entry)
if (entry->seg_count) {
for (i = 0; i < entry->seg_count; i++) {
if (entry->seglist[i]) {
drm_free_pages(entry->seglist[i],
entry->page_order, DRM_MEM_DMA);
drm_pci_free(dev, entry->seglist[i]);
}
}
drm_free(entry->seglist,
Expand Down Expand Up @@ -678,7 +677,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
int total;
int page_order;
drm_buf_entry_t *entry;
unsigned long page;
drm_dma_handle_t *dmah;
drm_buf_t *buf;
int alignment;
unsigned long offset;
Expand Down Expand Up @@ -781,8 +780,10 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
page_count = 0;

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. */
entry->buf_count = count;
entry->seg_count = count;
Expand All @@ -794,13 +795,13 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
atomic_dec(&dev->buf_alloc);
return -ENOMEM;
}
entry->seglist[entry->seg_count++] = page;
entry->seglist[entry->seg_count++] = dmah;
for (i = 0; i < (1 << page_order); i++) {
DRM_DEBUG("page %d @ 0x%08lx\n",
dma->page_count + page_count,
page + PAGE_SIZE * i);
(unsigned long)dmah->vaddr + PAGE_SIZE * i);
temp_pagelist[dma->page_count + page_count++]
= page + PAGE_SIZE * i;
= (unsigned long)dmah->vaddr + PAGE_SIZE * i;
}
for (offset = 0;
offset + size <= total && entry->buf_count < count;
Expand All @@ -811,7 +812,8 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
buf->order = order;
buf->used = 0;
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->waiting = 0;
buf->pending = 0;
Expand Down
4 changes: 1 addition & 3 deletions drivers/char/drm/drm_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,7 @@ void drm_dma_takedown(drm_device_t * dev)
dma->bufs[i].seg_count);
for (j = 0; j < dma->bufs[i].seg_count; j++) {
if (dma->bufs[i].seglist[j]) {
drm_free_pages(dma->bufs[i].seglist[j],
dma->bufs[i].page_order,
DRM_MEM_DMA);
drm_pci_free(dev, dma->bufs[i].seglist[j]);
}
}
drm_free(dma->bufs[i].seglist,
Expand Down
29 changes: 25 additions & 4 deletions drivers/char/drm/drm_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
drm_dma_handle_t *dmah;
#if 1
unsigned long addr;
size_t sz;
#endif
#ifdef DRM_DEBUG_MEMORY
int area = DRM_MEM_DMA;

Expand Down Expand Up @@ -79,7 +83,7 @@ drm_dma_handle_t *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align,
return NULL;

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
if (dmah->vaddr == NULL) {
Expand All @@ -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);

/* 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;
}

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.
*/
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
int area = DRM_MEM_DMA;
int alloc_count;
Expand All @@ -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");
#endif
} else {
pci_free_consistent(dev->pdev, dmah->size, dmah->vaddr,
dmah->busaddr);
/* 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);
}

#ifdef DRM_DEBUG_MEMORY
Expand Down

0 comments on commit ddf19b9

Please sign in to comment.