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>
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 107df9f..dbe952f 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -357,6 +357,12 @@
 	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.
  */
@@ -366,7 +372,7 @@
 	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;
@@ -483,12 +489,6 @@
 	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
  */
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index e2637b4..8a9cf12 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -474,8 +474,7 @@
 	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,
@@ -678,7 +677,7 @@
 	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;
@@ -781,8 +780,10 @@
 	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;
@@ -794,13 +795,13 @@
 			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;
@@ -811,7 +812,8 @@
 			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;
diff --git a/drivers/char/drm/drm_dma.c b/drivers/char/drm/drm_dma.c
index 2afab95..892db70 100644
--- a/drivers/char/drm/drm_dma.c
+++ b/drivers/char/drm/drm_dma.c
@@ -85,9 +85,7 @@
 				  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,
diff --git a/drivers/char/drm/drm_pci.c b/drivers/char/drm/drm_pci.c
index 1fd7ff16..b28ca9c 100644
--- a/drivers/char/drm/drm_pci.c
+++ b/drivers/char/drm/drm_pci.c
@@ -50,6 +50,10 @@
 				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;
 
@@ -79,7 +83,7 @@
 		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) {
@@ -104,18 +108,29 @@
 
 	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;
@@ -127,8 +142,14 @@
 		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