Hence, DRM needs a way to unmangle these values to get the physical
address back. Today, agpgart exports a "page_mask" value, so DRM does the
equivalent of this:
paddr = agpmem->memory->memory[offset] & dev->agp->page_mask;
This isn't sufficient for the 460GX, because its mangling function
requires a shift as well as a mask. The 460GX code (which is still in the
ia64 patch, not in the mainstream kernel) looks like this:
paddr = (agpmem->memory->memory[offset] & 0xffffff) << 12;
So DRM currently has chipset-specific code in it to unmangle the values in
memory[], while there's no reason for the mangled values to ever be
exported from agpgart. Worse, at least one soon-to-be-released IA64 box
has an unmangling function different from the 460GX.
The attached patch against 2.5.2-pre11 remedies all this by leaving the
plain physical addresses in memory[]. The chipset-specific mangling is
then done at the point where it is needed, when those values are inserted
into the GATT.
The patch is done so that agpgart still exports a page_mask; it's just
~0UL, so that old DRM modules will continue to work with new kernels.
These places are marked with "#ifdef EXPORT_PAGE_MASK" so it can be pulled
out eventually. New DRM modules will also work with old kernels, because
they still use page_mask (under "#ifdef USE_PAGE_MASK").
-- Bjorn Helgaas - bjorn_helgaas@hp.com Linux Systems Operation R&D Hewlett-Packard
diff -u -ur -X /home/helgaas/exclude linux-2.5.2-pre11/include/linux/agp_backend.h linux-2.5.2-pre11+pagemask/include/linux/agp_backend.h --- linux-2.5.2-pre11/include/linux/agp_backend.h Fri Nov 9 15:11:15 2001 +++ linux-2.5.2-pre11+pagemask/include/linux/agp_backend.h Fri Jan 11 11:02:15 2002 @@ -38,6 +38,13 @@ #define AGPGART_VERSION_MAJOR 0 #define AGPGART_VERSION_MINOR 99 +/* + * Old kernels exported mangled page addresses to DRM, which used + * page_mask to unmangle them. Old DRM, such as that distributed with + * XFree86, requires the page_mask. + */ +#define EXPORT_PAGE_MASK 1 + enum chipset_type { NOT_SUPPORTED, INTEL_GENERIC, @@ -92,7 +99,9 @@ int max_memory; /* In pages */ int current_memory; int cant_use_aperture; +#ifdef EXPORT_PAGE_MASK unsigned long page_mask; +#endif } agp_kern_info; /* diff -u -ur -X /home/helgaas/exclude linux-2.5.2-pre11/drivers/char/agp/agpgart_be.c linux-2.5.2-pre11+pagemask/drivers/char/agp/agpgart_be.c --- linux-2.5.2-pre11/drivers/char/agp/agpgart_be.c Fri Nov 30 09:52:41 2001 +++ linux-2.5.2-pre11+pagemask/drivers/char/agp/agpgart_be.c Fri Jan 11 11:20:36 2002 @@ -207,7 +207,6 @@ } if (curr->page_count != 0) { for (i = 0; i < curr->page_count; i++) { - curr->memory[i] &= ~(0x00000fff); agp_bridge.agp_destroy_page((unsigned long) phys_to_virt(curr->memory[i])); } @@ -260,10 +259,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++; } @@ -307,9 +303,6 @@ void agp_copy_info(agp_kern_info * info) { - unsigned long page_mask = 0; - int i; - memset(info, 0, sizeof(agp_kern_info)); if (agp_bridge.type == NOT_SUPPORTED) { info->chipset = agp_bridge.type; @@ -325,11 +318,9 @@ info->max_memory = agp_bridge.max_memory_agp; info->current_memory = atomic_read(&agp_bridge.current_memory_agp); info->cant_use_aperture = agp_bridge.cant_use_aperture; - - for(i = 0; i < agp_bridge.num_of_masks; i++) - page_mask |= agp_bridge.mask_memory(page_mask, i); - - info->page_mask = ~page_mask; +#ifdef EXPORT_PAGE_MASK + info->page_mask = ~0UL; +#endif } /* End - Routine to copy over information structure */ @@ -746,7 +737,8 @@ 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); @@ -983,7 +975,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(); @@ -1049,10 +1042,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; @@ -1086,7 +1076,6 @@ intel_i810_private.i810_dev = i810_dev; agp_bridge.masks = intel_i810_masks; - agp_bridge.num_of_masks = 2; agp_bridge.aperture_sizes = (void *) intel_i810_sizes; agp_bridge.size_type = FIXED_APER_SIZE; agp_bridge.num_aperture_sizes = 2; @@ -1288,7 +1277,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(); @@ -1349,7 +1339,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; @@ -1365,7 +1355,6 @@ intel_i830_private.i830_dev = i830_dev; agp_bridge.masks = intel_i810_masks; - agp_bridge.num_of_masks = 3; agp_bridge.aperture_sizes = (void *) intel_i830_sizes; agp_bridge.size_type = FIXED_APER_SIZE; agp_bridge.num_aperture_sizes = 2; @@ -1784,7 +1773,6 @@ static int __init intel_generic_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_generic_sizes; agp_bridge.size_type = U16_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -1818,7 +1806,6 @@ static int __init intel_820_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -1878,7 +1865,6 @@ static int __init intel_840_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -1911,7 +1897,6 @@ static int __init intel_845_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -1944,7 +1929,6 @@ static int __init intel_850_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -1977,7 +1961,6 @@ static int __init intel_860_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -2097,7 +2080,6 @@ static int __init via_generic_setup (struct pci_dev *pdev) { agp_bridge.masks = via_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) via_generic_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -2211,7 +2193,6 @@ static int __init sis_generic_setup (struct pci_dev *pdev) { agp_bridge.masks = sis_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) sis_generic_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -2543,7 +2524,8 @@ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; cur_gatt = GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i]; + cur_gatt[GET_GATT_OFF(addr)] = + agp_bridge.mask_memory(mem->memory[i], mem->type); } agp_bridge.tlb_flush(mem); return 0; @@ -2589,7 +2571,6 @@ static int __init amd_irongate_setup (struct pci_dev *pdev) { agp_bridge.masks = amd_irongate_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) amd_irongate_sizes; agp_bridge.size_type = LVL2_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -2837,7 +2818,6 @@ static int __init ali_generic_setup (struct pci_dev *pdev) { agp_bridge.masks = ali_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) ali_generic_sizes; agp_bridge.size_type = U32_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -3245,7 +3225,8 @@ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; cur_gatt = SVRWRKS_GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i]; + cur_gatt[GET_GATT_OFF(addr)] = + agp_bridge.mask_memory(mem->memory[i], mem->type); } agp_bridge.tlb_flush(mem); return 0; @@ -3425,7 +3406,6 @@ serverworks_private.svrwrks_dev = pdev; agp_bridge.masks = serverworks_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) serverworks_sizes; agp_bridge.size_type = LVL2_APER_SIZE; agp_bridge.num_aperture_sizes = 7; diff -u -ur -X /home/helgaas/exclude linux-2.5.2-pre11/drivers/char/drm/drmP.h linux-2.5.2-pre11+pagemask/drivers/char/drm/drmP.h --- linux-2.5.2-pre11/drivers/char/drm/drmP.h Sun Dec 16 16:43:58 2001 +++ linux-2.5.2-pre11+pagemask/drivers/char/drm/drmP.h Fri Jan 11 11:07:28 2002 @@ -76,6 +76,11 @@ #include <asm/pgalloc.h> #include "drm.h" +/* page_mask required for old kernels that export mangled page addrs */ +/* when the mainline kernel no longer exports mangled addrs, this can be + * under "#if LINUX_VERSION_CODE < ..." */ +#define USE_PAGE_MASK 1 + /* page_to_bus for earlier kernels, not optimal in all cases */ #ifndef page_to_bus #define page_to_bus(page) ((unsigned int)(virt_to_bus(page_address(page)))) @@ -628,7 +633,9 @@ unsigned long base; int agp_mtrr; int cant_use_aperture; +#ifdef USE_PAGE_MASK unsigned long page_mask; +#endif } drm_agp_head_t; #endif diff -u -ur -X /home/helgaas/exclude linux-2.5.2-pre11/drivers/char/drm/drm_agpsupport.h linux-2.5.2-pre11+pagemask/drivers/char/drm/drm_agpsupport.h --- linux-2.5.2-pre11/drivers/char/drm/drm_agpsupport.h Sun Dec 16 16:43:58 2001 +++ linux-2.5.2-pre11+pagemask/drivers/char/drm/drm_agpsupport.h Fri Jan 11 11:01:11 2002 @@ -323,7 +323,9 @@ head->page_mask = ~(0xfff); #else head->cant_use_aperture = head->agp_info.cant_use_aperture; +#ifdef USE_PAGE_MASK head->page_mask = head->agp_info.page_mask; +#endif #endif DRM_INFO("AGP %d.%d on %s @ 0x%08lx %ZuMB\n", diff -u -ur -X /home/helgaas/exclude linux-2.5.2-pre11/drivers/char/drm/drm_vm.h linux-2.5.2-pre11+pagemask/drivers/char/drm/drm_vm.h --- linux-2.5.2-pre11/drivers/char/drm/drm_vm.h Sun Dec 16 16:43:58 2001 +++ linux-2.5.2-pre11+pagemask/drivers/char/drm/drm_vm.h Fri Jan 11 11:01:24 2002 @@ -115,7 +115,9 @@ * Get the page, inc the use count, and return it */ offset = (baddr - agpmem->bound) >> PAGE_SHIFT; +#ifdef USE_PAGE_MASK agpmem->memory->memory[offset] &= dev->agp->page_mask; +#endif page = virt_to_page(__va(agpmem->memory->memory[offset])); get_page(page); - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/