Skip to contentSkip to conversation

ppc32 (linux-2.6.11.4): remove the limitation of 2MB consistent DMA memory on ppc440

RFC PATCH New Shawn Jin 1 participant 1 message Jun 1, 2005 1 message not in the archive

lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): 1B5A11557D6A86458B1AD15DBBDB6CE2066D8CF4@tayexc13.americas.cpqcorp.net

Shawn Jin

author
#1 lore raw

RFC PATCH 1/1 ppc32 (linux-2.6.11.4): remove the limitation of 2MB consistent DMA memory on ppc440

Hi,

This patch removes the limitation of 2MB consistent DMA memory on ppc440. Originally consistent_pte was allocated only one page no matter what value of CONFIG_CONSISTENT_SIZE is set. By default CONFIG_CONSISTENT_SIZE is 0x200000. This causes some troubles on high performance I/O applications which may require more than 2MB consistent DMA memory.

The modifications allocate multiple pages for consistent pte table according to CONFIG_CONSISTENT_SIZE. For example if CONFIG_CONSISTENT_SIZE is set to 4MB, 2 pages are allocated for consistent pte table. Please note that CONFIG_CONSISTENT_SIZE cannot be any value. You have to find a free continuous memory space on your system memory mapping.

The patch was tested successfully on Ocotea board. But I'm not sure if it works on other systems. Use it at your own risk. However feedback is more than welcome. :)

Regards,
-Shawn.

arch/ppc/kernel/dma-mapping.c renamed from linux-2.6.11.4/arch/ppc/kernel/dma-mapping.c +52 -12
@@ -17,6 +17,11 @@
  * implementation. This is pulled straight from ARM and barely
  * modified. -Matt
  *
+ * Changed consistent_pte to consistent_ptes, in order to remove the 
+ * limitation of 2MB consistent DMA memory. Now the size is confined by
+ * CONFIG_CONSISTENT_SIZE. And there are multiple pages containing PTE.
+ * - Xiaogeng (Shawn) Jin (Agilent Technologies), 2005
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -66,11 +71,14 @@
 #define CONSISTENT_BASE	(CONFIG_CONSISTENT_START)
 #define CONSISTENT_END	(CONFIG_CONSISTENT_START + CONFIG_CONSISTENT_SIZE)
 #define CONSISTENT_OFFSET(x)	(((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT)
+#define	CONSISTENT_PTE_PAGENR	((CONFIG_CONSISTENT_SIZE >> PAGE_SHIFT) >> PTE_SHIFT)
+#define CONSISTENT_SIZE_PER_PTEPAGE	(1UL << (PAGE_SHIFT + PTE_SHIFT))
 
 /*
- * This is the page table (2MB) covering uncached, DMA consistent allocations
+ * This is page tables covering uncached, DMA consistent allocations,
+ * with the size of CONFIG_CONSISTENT_SIZE
  */
-static pte_t *consistent_pte;
+pte_t **consistent_ptes = NULL;
 static DEFINE_SPINLOCK(consistent_lock);
 
 /*
@@ -180,7 +188,7 @@
 	unsigned long order;
 	u64 mask = 0x00ffffff, limit; /* ISA default */
 
-	if (!consistent_pte) {
+	if (!consistent_ptes) {
 		printk(KERN_ERR "%s: not initialised\n", __func__);
 		dump_stack();
 		return NULL;
@@ -219,9 +227,14 @@
 	c = vm_region_alloc(&consistent_head, size,
 			    gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
 	if (c) {
-		pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
+		pte_t *pte;
+		int offset = CONSISTENT_OFFSET(c->vm_start);
+		int idx = offset >> PTE_SHIFT;
 		struct page *end = page + (1 << order);
 
+		offset &= (1 << PTE_SHIFT) - 1;
+		pte = consistent_ptes[idx] + offset;
+
 		/*
 		 * Set the "dma handle"
 		 */
@@ -235,6 +248,11 @@
 			set_pte(pte, mk_pte(page, pgprot_noncached(PAGE_KERNEL)));
 			page++;
 			pte++;
+			offset++;
+			if (offset > ((1 << PTE_SHIFT) - 1)) {
+				pte = consistent_ptes[++idx];
+				offset = 0;
+			}
 		} while (size -= PAGE_SIZE);
 
 		/*
@@ -264,6 +282,7 @@
 	struct vm_region *c;
 	unsigned long flags;
 	pte_t *ptep;
+	int offset, idx;
 
 	size = PAGE_ALIGN(size);
 
@@ -280,12 +299,21 @@
 		size = c->vm_end - c->vm_start;
 	}
 
-	ptep = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
+	offset = CONSISTENT_OFFSET(c->vm_start);
+	idx = offset >> PTE_SHIFT;
+	offset &= (1 << PTE_SHIFT) - 1;
+	ptep = consistent_ptes[idx] + offset;
+
 	do {
 		pte_t pte = ptep_get_and_clear(ptep);
 		unsigned long pfn;
 
 		ptep++;
+		offset++;
+		if (offset > ((1 << PTE_SHIFT) - 1)) {
+			ptep = consistent_ptes[++idx];
+			offset = 0;
+		}
 
 		if (!pte_none(pte) && pte_present(pte)) {
 			pfn = pte_pfn(pte);
@@ -328,13 +356,22 @@
 	pgd_t *pgd;
 	pmd_t *pmd;
 	pte_t *pte;
-	int ret = 0;
+	int ret = 0, i;
+	unsigned long address;
 
 	spin_lock(&init_mm.page_table_lock);
 
-	do {
-		pgd = pgd_offset(&init_mm, CONSISTENT_BASE);
-		pmd = pmd_alloc(&init_mm, pgd, CONSISTENT_BASE);
+	consistent_ptes = (pte_t **)kmalloc(sizeof(pte_t **) * 
+					CONSISTENT_PTE_PAGENR, GFP_KERNEL);
+	if (!consistent_ptes) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	
+	for (i = 0, address = CONSISTENT_BASE; i < CONSISTENT_PTE_PAGENR; i++) {
+		pgd = pgd_offset(&init_mm, address);
+		pmd = pmd_alloc(&init_mm, pgd, address);
 		if (!pmd) {
 			printk(KERN_ERR "%s: no pmd tables\n", __func__);
 			ret = -ENOMEM;
@@ -342,16 +379,19 @@
 		}
 		WARN_ON(!pmd_none(*pmd));
 
-		pte = pte_alloc_kernel(&init_mm, pmd, CONSISTENT_BASE);
+		pte = pte_alloc_kernel(&init_mm, pmd, address);
 		if (!pte) {
 			printk(KERN_ERR "%s: no pte tables\n", __func__);
 			ret = -ENOMEM;
 			break;
 		}
 
-		consistent_pte = pte;
-	} while (0);
+		consistent_ptes[i] = pte;
+
+		address += CONSISTENT_SIZE_PER_PTEPAGE;
+	}
 
+out:
 	spin_unlock(&init_mm.page_table_lock);
 
 	return ret;