On Sunday 09 December 2001 10:28 pm, you wrote:
> And this is true about the kernel-level API as well. I have just figured
> out that agp_memory_t.memory field is an array of addresses to allocated
> pages - but I have not figured out whether these are physical or not.

The memory[] table currently contains the values stored in the GATT (the
hardware-visible translation table).  Typically this is the physical
address plus a bit or two to indicate a valid entry.  In order to get the
actual physical address, you have to strip out those extra bits ("unmask"
in agpgart terminology).

I am proposing a patch that will make the memory[] values genuine physical
addresses, with no extra bits.  The Geocrawler list archive seems
hopelessly hosed, so I'll attach a couple recent messages about it.

Bjorn
--
Linux Systems Operation R&D
Hewlett-Packard
Fort Collins, CO

--- Begin Message ---
In the Linux AGP/GART driver, the agp_memory struct contains a memory[] 
array with the physical address of every page in the block.

Currently, the elements of the memory[] array are the actual values put 
into the GATT, i.e., they contain the valid bit and any other bits 
required by the GART chipset as well as the physical address.

These mangled physical addresses are used by DRM, for example in 
DRM(vm_nopage), where those extra chipset-specific bits have to be masked 
out to obtain the actual physical address.

I propose a change along the lines of the following patch, which makes the 
elements of memory[] plain physical addresses and keeps all the 
chipset-specific bits encapsulated inside the AGP/GART module.  The 
general idea is to move the "masking" (chipset-specific address mangling) 
from the memory allocation path to the GATT insertion path.

I'm not a DRM guru, so I'm sure there are subtleties I'm missing, and I 
know there are some interface versioning issues to work out, but I'd 
appreciate any feedback on the approach and advice on how to proceed.  The 
attached patch is against 2.4.16 with the IA64 patch applied.


--- linux+ia64/drivers/char/drm/drmP.h  Tue Nov 27 13:54:53 2001
+++ linux/drivers/char/drm/drmP.h       Thu Dec  6 14:11:34 2001
@@ -628,7 +628,9 @@
        unsigned long      base;
        int                agp_mtrr;
        int                cant_use_aperture;
+#ifdef PAGE_MASK_INTERFACE
        unsigned long      page_mask;
+#endif
 } drm_agp_head_t;
 #endif
 
--- linux+ia64/drivers/char/drm/drm_vm.h        Tue Nov 27 13:54:53 2001
+++ linux/drivers/char/drm/drm_vm.h     Thu Dec  6 10:57:39 2001
@@ -115,18 +115,7 @@
                  * Get the page, inc the use count, and return it
                  */
                offset = (baddr - agpmem->bound) >> PAGE_SHIFT;
-
-               /*
-                * This is bad.  What we really want to do here is unmask
-                * the GART table entry held in the agp_memory structure.
-                * There isn't a convenient way to call agp_bridge.unmask_
-                * memory from here, so hard code it for now.
-                */
-#if defined(__ia64__)
-               paddr = (agpmem->memory->memory[offset] & 0xffffff) << 12;
-#else
-               paddr = agpmem->memory->memory[offset] & dev->agp->page_mask;
-#endif
+               paddr = agpmem->memory->memory[offset];
                page = virt_to_page(__va(paddr));
                get_page(page);
 
--- linux+ia64/drivers/char/drm/drm_agpsupport.h        Tue Nov 27 13:54:53 2001
+++ linux/drivers/char/drm/drm_agpsupport.h     Thu Dec  6 10:56:34 2001
@@ -321,10 +321,14 @@
                }
 #if LINUX_VERSION_CODE <= 0x020408
                head->cant_use_aperture = 0;
+#ifdef PAGE_MASK_INTERFACE
                head->page_mask = ~(0xfff);
+#endif
 #else
                head->cant_use_aperture = head->agp_info.cant_use_aperture;
+#ifdef PAGE_MASK_INTERFACE
                head->page_mask = head->agp_info.page_mask;
+#endif
 #endif
 
                DRM_INFO("AGP %d.%d on %s @ 0x%08lx %ZuMB\n",
--- linux+ia64/drivers/char/agp/agpgart_be.c    Tue Nov 27 13:54:53 2001
+++ linux/drivers/char/agp/agpgart_be.c Thu Dec  6 10:59:51 2001
@@ -212,8 +212,6 @@
        if(agp_bridge.cant_use_aperture == 0) {
                if (curr->page_count != 0) {
                        for (i = 0; i < curr->page_count; i++) {
-                               curr->memory[i] = agp_bridge.unmask_memory(
-                                                            curr->memory[i]);
                                agp_bridge.agp_destroy_page((unsigned long)
                                                 phys_to_virt(curr->memory[i]));
                        }
@@ -302,10 +300,7 @@
                                agp_free_memory(new);
                                return NULL;
                        }
-                       new->memory[i] =
-                           agp_bridge.mask_memory(
-                                         virt_to_phys((void *) new->memory[i]),
-                                                         type);
+                       new->memory[i] = virt_to_phys((void *) new->memory[i]);
                        new->page_count++;
                }
        } else {
@@ -338,7 +333,7 @@
 #else
                        paddr = pte_val(*pte) & PAGE_MASK;
 #endif
-                       new->memory[i] = agp_bridge.mask_memory(paddr, type);
+                       new->memory[i] = paddr;
                }
 
                new->page_count = page_count;
@@ -403,10 +398,12 @@
        info->current_memory = atomic_read(&agp_bridge.current_memory_agp);
        info->cant_use_aperture = agp_bridge.cant_use_aperture;
 
+#ifdef PAGE_MASK_INTERFACE
        for(i = 0; i < agp_bridge.num_of_masks; i++)
                page_mask |= agp_bridge.mask_memory(page_mask, i);
 
        info->page_mask = ~page_mask;
+#endif
 }
 
 /* End - Routine to copy over information structure */
@@ -825,7 +822,7 @@
                mem->is_flushed = TRUE;
        }
        for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-               agp_bridge.gatt_table[j] = mem->memory[i];
+               agp_bridge.gatt_table[j] = agp_bridge.mask_memory(mem->memory[i], 
mem->type);
        }
 
        agp_bridge.tlb_flush(mem);
@@ -1067,7 +1064,8 @@
        CACHE_FLUSH();
        for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
                OUTREG32(intel_i810_private.registers,
-                        I810_PTE_BASE + (j * 4), mem->memory[i]);
+                        I810_PTE_BASE + (j * 4),
+                        agp_bridge.mask_memory(mem->memory[i], mem->type));
        }
        CACHE_FLUSH();
 
@@ -1133,10 +1131,7 @@
                        agp_free_memory(new);
                        return NULL;
                }
-               new->memory[0] =
-                   agp_bridge.mask_memory(
-                                  virt_to_phys((void *) new->memory[0]),
-                                                 type);
+               new->memory[0] = virt_to_phys((void *) new->memory[0]);
                new->page_count = 1;
                new->num_scratch_pages = 1;
                new->type = AGP_PHYS_MEMORY;
@@ -1373,7 +1368,8 @@
        CACHE_FLUSH();
 
        for (i = 0, j = pg_start; i < mem->page_count; i++, j++)
-               OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 
4),mem->memory[i]);
+               OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),
+                        agp_bridge.mask_memory(mem->memory[i], mem->type));
 
        CACHE_FLUSH();
 
@@ -1434,7 +1430,7 @@
                        return(NULL);
                }
 
-               nw->memory[0] = agp_bridge.mask_memory(virt_to_phys((void *) 
nw->memory[0]),type);
+               nw->memory[0] = virt_to_phys((void *) nw->memory[0]);
                nw->page_count = 1;
                nw->num_scratch_pages = 1;
                nw->type = AGP_PHYS_MEMORY;
@@ -1485,10 +1481,6 @@
 
 #endif /* CONFIG_AGP_I810 */
  
- #ifdef CONFIG_AGP_INTEL
-
-#endif /* CONFIG_AGP_I810 */
-
 #ifdef CONFIG_AGP_I460
 
 /* BIOS configures the chipset so that one of two apbase registers are 
used */
@@ -1496,6 +1488,7 @@
 
 /* 460 supports multiple GART page sizes, so GART pageshift is dynamic */ 
 static u8 intel_i460_pageshift = 12;
+static u32 intel_i460_pagesize;
 
 /* Keep track of which is larger, chipset or kernel page size. */
 static u32 intel_i460_cpk = 1;
@@ -1523,6 +1516,7 @@
        /* Determine the GART page size */
        pci_read_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, &temp);
        intel_i460_pageshift = (temp & I460_4M_PS) ? 22 : 12;
+       intel_i460_pagesize = 1UL << intel_i460_pageshift;
 
        values = A_SIZE_8(agp_bridge.aperture_sizes);
 
@@ -1737,7 +1731,7 @@
 {
        int i, j, k, num_entries;
        void *temp;
-       unsigned int hold;
+       unsigned long paddr;
        unsigned int read_back;
 
        /* 
@@ -1769,10 +1763,11 @@
 
        for (i = 0, j = pg_start; i < mem->page_count; i++) {
 
-               hold = (unsigned int) (mem->memory[i]);
+               paddr = mem->memory[i];
 
-               for (k = 0; k < I460_CPAGES_PER_KPAGE; k++, j++, hold++)
-                       agp_bridge.gatt_table[j] = hold;
+               for (k = 0; k < I460_CPAGES_PER_KPAGE; k++, j++, paddr += 
intel_i460_pagesize)
+                       agp_bridge.gatt_table[j] = (unsigned int)
+                           agp_bridge.mask_memory(paddr, mem->type);
        }
 
        /* 
@@ -1886,6 +1881,7 @@
        int num_entries;        
        void *temp;
        unsigned int read_back;
+       unsigned long paddr;
 
        temp = agp_bridge.current_size;
        num_entries = A_SIZE_8(temp)->num_entries;
@@ -1934,18 +1930,17 @@
 
        for(pg = start_pg, i = 0; pg <= end_pg; pg++)
        {
+               paddr = agp_bridge.unmask_memory(agp_bridge.gatt_table[pg]);
                for(idx = ((pg == start_pg) ? start_offset : 0);
                    idx < ((pg == end_pg) ? (end_offset + 1)
                                       : I460_KPAGES_PER_CPAGE);
                    idx++, i++)
                {
-                       i460_pg_detail[pg][idx] = agp_bridge.gatt_table[pg] + 
-                                                     ((idx * PAGE_SIZE) >> 12);
+                       mem->memory[i] = paddr + (idx * PAGE_SIZE);
+                       i460_pg_detail[pg][idx] =
+                           agp_bridge.mask_memory(mem->memory[i], mem->type);
+                           
                        i460_pg_count[pg]++;
-
-                       /* Finally we fill in mem->memory... */
-                       mem->memory[i] = ((unsigned long) (0xffffff & 
-                                               i460_pg_detail[pg][idx])) << 12;
                }
        }
 
@@ -1959,7 +1954,7 @@
        int num_entries;
        void *temp;
        unsigned int read_back;
-       unsigned long addr;
+       unsigned long paddr;
 
        temp = agp_bridge.current_size;
        num_entries = A_SIZE_8(temp)->num_entries;
@@ -1986,13 +1981,11 @@
 
                /* Free GART pages if they are unused */
                if(i460_pg_count[pg] == 0) {
-                       addr = (0xffffffUL & (unsigned long) 
-                                            (agp_bridge.gatt_table[pg])) << 12;
-
-                       agp_bridge.gatt_table[pg] = 0;
+                       paddr = agp_bridge.unmask_memory(agp_bridge.gatt_table[pg]);
+                       agp_bridge.gatt_table[pg] = agp_bridge.scratch_page;
                        read_back = agp_bridge.gatt_table[pg];
 
-                       intel_i460_free_large_page(pg, addr);
+                       intel_i460_free_large_page(pg, paddr);
                }
        }
                


--- End Message ---
--- Begin Message ---
On Friday 07 December 2001 2:09 am, Keith Whitwell wrote:
> What are the goals of your patch?  Is it a cleanup, or is there
> something deeper you hope to gain?

Yes, I should have made the goal clearer.   This section of the diff is 
the relevant piece:

--- linux+ia64/drivers/char/drm/drm_vm.h        Tue Nov 27 13:54:53 2001
+++ linux/drivers/char/drm/drm_vm.h     Thu Dec  6 10:57:39 2001
@@ -115,18 +115,7 @@
                  * Get the page, inc the use count, and return it
                  */
                offset = (baddr - agpmem->bound) >> PAGE_SHIFT;
-
-               /*
-                * This is bad.  What we really want to do here is unmask
-                * the GART table entry held in the agp_memory structure.
-                * There isn't a convenient way to call agp_bridge.unmask_
-                * memory from here, so hard code it for now.
-                */
-#if defined(__ia64__)
-               paddr = (agpmem->memory->memory[offset] & 0xffffff) << 12;
-#else
-               paddr = agpmem->memory->memory[offset] & 
dev->agp->page_mask;
-#endif
+               paddr = agpmem->memory->memory[offset];
                page = virt_to_page(__va(paddr));
                get_page(page);
 
Note that the computation of paddr is machine-dependent.  The existing 
code for __ia64__ (paddr = (agpmem->memory->memory[offset] & 0xffffff) << 
12) is specific to the Intel 460GX chipset.  I'm implementing support for 
an HP IA64 chipset, and our unmasking function is of course different from 
the 460's.

So, we either have to have chipset-specific code in DRM to compute paddr, 
or export an API from AGP/GART (the page_mask stuff is a simple start at 
this, but as you can see, is not general enough to describe all unmask 
operations), or try to remove the need for the unmasking completely.

This last is the avenue that I'm trying to pursue.  The unmask operation 
is chipset-dependent, and ideally would be encapsulated within the 
AGP/GART module.  I don't see any reason why the memory[] table needs to 
contain the "masked" values, so I simply put the unmasked values there 
(the unmodified physical addresses).

The place where the masked values are needed is when they are actually 
inserted in the GATT, the table read by the chipset.  Before my patch, the 
memory allocation functions apply the mask operation and put the result 
into memory[].  The functions that insert into the GATT just copied the 
values from memory[].  My patch changes things so that the memory 
allocation functions do not apply the mask, but rather put the unmodified 
physical addresses into memory[].  The GATT insertion functions then take 
the values from memory[], apply the mask operation, *then* put them into 
the GATT.

Make sense?

_______________________________________________
Dri-devel mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/dri-devel


--- End Message ---

Reply via email to