[PATCH 12/23] agp/intel-gtt: Utilize the PCI DMA for i8xxx,

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: Konrad Rzeszutek Wilk
Date: Monday, December 6, 2010 - 4:24 pm

The AGP drivers for newer chipsets (ICH9 and higher) use
the PCI DMA and get the proper bus address.

For older "legacy" code (say ICH5), this has not been done.
To make those chipsets work properly, we need to program the
bus address of the pages in GATT with the correct address.

When running under Xen, the old trick of PFN << PAGE_SIZE == phys
does not work as the PFN is not neccessary equal to the "real" hardware
PFN (called 'MFN'). As such we need to use the PCI API.

Currently the code works alongside the newer code that
uses scatterlist. In the future we can squish those together.

Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
---
 drivers/char/agp/intel-gtt.c |   54 +++++++++++++++++++++++++++++++-----------
 1 files changed, 40 insertions(+), 14 deletions(-)

diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index dcd8894..e984559 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -248,17 +248,21 @@ static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode)
 }
 
 /* Exists to support ARGB cursors */
-static struct page *i8xx_alloc_pages(void)
+static struct page *i8xx_alloc_pages(dma_addr_t *dma_addr)
 {
 	struct page *page;
+	void *addr;
 
-	page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2);
-	if (page == NULL)
+	addr = pci_alloc_consistent(intel_private.pcidev, 4 * PAGE_SIZE,
+				    dma_addr);
+	if (addr == NULL)
 		return NULL;
-
+	page = virt_to_page(addr);
 	if (set_pages_uc(page, 4) < 0) {
 		set_pages_wb(page, 4);
-		__free_pages(page, 2);
+		pci_free_consistent(intel_private.pcidev, 4 * PAGE_SIZE,
+				    addr, *dma_addr);
+		*dma_addr = DMA_ERROR_CODE;
 		return NULL;
 	}
 	get_page(page);
@@ -266,14 +270,18 @@ static struct page *i8xx_alloc_pages(void)
 	return page;
 }
 
-static void i8xx_destroy_pages(struct page *page)
+static void i8xx_destroy_pages(struct page *page, dma_addr_t *dma_addr)
 {
+	void *addr;
 	if (page == NULL)
 		return;
 
 	set_pages_wb(page, 4);
 	put_page(page);
-	__free_pages(page, 2);
+	addr = page_address(page);
+	pci_free_consistent(intel_private.pcidev, 4 * PAGE_SIZE,
+			    addr, *dma_addr);
+	*dma_addr = DMA_ERROR_CODE;
 	atomic_dec(&agp_bridge->current_memory_agp);
 }
 
@@ -322,8 +330,14 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
 		if (!mem->is_flushed)
 			global_cache_flush();
 		for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+			dma_addr_t addr = mem->dma_addr[i];
+			if (addr == DMA_ERROR_CODE) {
+				WARN_ONCE(1, "Caller hasn't converted to DMA" \
+					  "API!\n");
+				addr = page_to_phys(mem->pages[i]);
+			}
 			writel(agp_bridge->driver->mask_memory(agp_bridge,
-					page_to_phys(mem->pages[i]), mask_type),
+					addr, mask_type),
 			       intel_private.registers+I810_PTE_BASE+(j*4));
 		}
 		readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
@@ -371,7 +385,7 @@ static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
 		break;
 	case 4:
 		/* kludge to get 4 physical pages for ARGB cursor */
-		page = i8xx_alloc_pages();
+		page = i8xx_alloc_pages(&dma_addr[0]);
 		break;
 	default:
 		return NULL;
@@ -385,11 +399,15 @@ static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
 		return NULL;
 
 	new->pages[0] = page;
+	new->dma_addr[0] = dma_addr[0];
 	if (pg_count == 4) {
 		/* kludge to get 4 physical pages for ARGB cursor */
 		new->pages[1] = new->pages[0] + 1;
 		new->pages[2] = new->pages[1] + 1;
 		new->pages[3] = new->pages[2] + 1;
+		new->dma_addr[1] = dma_addr[0] + PAGE_SIZE;
+		new->dma_addr[2] = dma_addr[1] + PAGE_SIZE;
+		new->dma_addr[3] = dma_addr[2] + PAGE_SIZE;
 	}
 	new->page_count = pg_count;
 	new->num_scratch_pages = pg_count;
@@ -426,7 +444,7 @@ static void intel_i810_free_by_type(struct agp_memory *curr)
 	agp_free_key(curr->key);
 	if (curr->type == AGP_PHYS_MEMORY) {
 		if (curr->page_count == 4)
-			i8xx_destroy_pages(curr->pages[0]);
+			i8xx_destroy_pages(curr->pages[0], &curr->dma_addr[0]);
 		else {
 			agp_bridge->driver->agp_destroy_page(curr->pages[0],
 							     AGP_PAGE_DESTROY_UNMAP,
@@ -451,10 +469,13 @@ static int intel_gtt_setup_scratch_page(void)
 {
 	struct page *page;
 	dma_addr_t dma_addr;
+	void *addr;
 
-	page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
-	if (page == NULL)
+	addr = pci_alloc_consistent(intel_private.pcidev, PAGE_SIZE, &dma_addr);
+	if (addr == NULL)
 		return -ENOMEM;
+
+	page = virt_to_page(addr);
 	get_page(page);
 	set_pages_uc(page, 1);
 
@@ -466,7 +487,7 @@ static int intel_gtt_setup_scratch_page(void)
 
 		intel_private.scratch_page_dma = dma_addr;
 	} else
-		intel_private.scratch_page_dma = page_to_phys(page);
+		intel_private.scratch_page_dma = dma_addr;
 
 	intel_private.scratch_page = page;
 
@@ -1031,7 +1052,12 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem,
 					    pg_start, type);
 	} else {
 		for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-			dma_addr_t addr = page_to_phys(mem->pages[i]);
+			dma_addr_t addr = mem->dma_addr[i];
+			if (addr == DMA_ERROR_CODE) {
+				WARN_ONCE(1, "Caller hasn't converted to DMA "\
+					  "API!\n");
+				addr = page_to_phys(mem->pages[i]);
+			}
 			intel_private.driver->write_entry(addr,
 							  j, type);
 		}
-- 
1.7.1

--
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
[RFC PATCH] Utilize the PCI API in the AGP framework., Konrad Rzeszutek Wilk, (Mon Dec 6, 4:24 pm)
[PATCH 08/23] agp/amd64: Use the dma_addr[] and gatt_bus_a ..., Konrad Rzeszutek Wilk, (Mon Dec 6, 4:24 pm)
[PATCH 09/23] agp/amd-k7: Utilize the PCI API for creating ..., Konrad Rzeszutek Wilk, (Mon Dec 6, 4:24 pm)
[PATCH 11/23] agp/serverworks: Utilize the PCI API for all ..., Konrad Rzeszutek Wilk, (Mon Dec 6, 4:24 pm)
[PATCH 12/23] agp/intel-gtt: Utilize the PCI DMA for i8xxx,, Konrad Rzeszutek Wilk, (Mon Dec 6, 4:24 pm)
[PATCH 20/23] ia64: Add DMA_ERROR_CODE define., Konrad Rzeszutek Wilk, (Mon Dec 6, 4:24 pm)
Re: [RFC PATCH] Utilize the PCI API in the AGP framework., Konrad Rzeszutek Wilk, (Mon Dec 6, 5:48 pm)
Re: [RFC PATCH] Utilize the PCI API in the AGP framework., Konrad Rzeszutek Wilk, (Mon Dec 6, 7:12 pm)
Re: [RFC PATCH] Utilize the PCI API in the AGP framework., Konrad Rzeszutek Wilk, (Wed Dec 8, 9:45 am)