[AGPGART] Allow drm-populated agp memory types
authorThomas Hellstrom <thomas@tungstengraphics.com>
Tue, 23 Jan 2007 09:33:43 +0000 (10:33 +0100)
committerDave Jones <davej@redhat.com>
Sat, 3 Feb 2007 22:16:24 +0000 (17:16 -0500)
This patch allows drm to populate an agpgart structure with pages of its own.
It's needed for the new drm memory manager which dynamically flips pages in and out of AGP.

The patch modifies the generic functions as well as the intel agp driver. The intel drm driver is
currently the only one supporting the new memory manager.

Other agp drivers may need some minor fixing up once they have a corresponding memory manager enabled drm driver.

AGP memory types >= AGP_USER_TYPES are not populated by the agpgart driver, but the drm is expected
to do that, as well as taking care of cache- and tlb flushing when needed.

It's not possible to request these types from user space using agpgart ioctls.

The Intel driver also gets a new memory type for pages that can be bound cached to the intel GTT.

Signed-off-by: Thomas Hellstrom <thomas@tungstengraphics.com>
Signed-off-by: Dave Jones <davej@redhat.com>
19 files changed:
drivers/char/agp/agp.h
drivers/char/agp/ali-agp.c
drivers/char/agp/alpha-agp.c
drivers/char/agp/amd-k7-agp.c
drivers/char/agp/amd64-agp.c
drivers/char/agp/ati-agp.c
drivers/char/agp/backend.c
drivers/char/agp/efficeon-agp.c
drivers/char/agp/frontend.c
drivers/char/agp/generic.c
drivers/char/agp/hp-agp.c
drivers/char/agp/i460-agp.c
drivers/char/agp/intel-agp.c
drivers/char/agp/nvidia-agp.c
drivers/char/agp/sgi-agp.c
drivers/char/agp/sworks-agp.c
drivers/char/agp/uninorth-agp.c
drivers/char/agp/via-agp.c
include/linux/agp_backend.h

index 7fc72d12e7be72e35d946895919b63ae5c620f1c..9bd68d9f0f5989105b6349ba98004d9cff381b2e 100644 (file)
@@ -114,6 +114,7 @@ struct agp_bridge_driver {
        void (*free_by_type)(struct agp_memory *);
        void *(*agp_alloc_page)(struct agp_bridge_data *);
        void (*agp_destroy_page)(void *);
+        int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
 };
 
 struct agp_bridge_data {
@@ -218,6 +219,7 @@ struct agp_bridge_data {
 #define I810_PTE_MAIN_UNCACHED 0x00000000
 #define I810_PTE_LOCAL         0x00000002
 #define I810_PTE_VALID         0x00000001
+#define I830_PTE_SYSTEM_CACHED  0x00000006
 #define I810_SMRAM_MISCC       0x70
 #define I810_GFX_MEM_WIN_SIZE  0x00010000
 #define I810_GFX_MEM_WIN_32M   0x00010000
@@ -270,8 +272,16 @@ void global_cache_flush(void);
 void get_agp_version(struct agp_bridge_data *bridge);
 unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge,
        unsigned long addr, int type);
+int agp_generic_type_to_mask_type(struct agp_bridge_data *bridge,
+                                 int type);
 struct agp_bridge_data *agp_generic_find_bridge(struct pci_dev *pdev);
 
+/* generic functions for user-populated AGP memory types */
+struct agp_memory *agp_generic_alloc_user(size_t page_count, int type);
+void agp_alloc_page_array(size_t size, struct agp_memory *mem);
+void agp_free_page_array(struct agp_memory *mem);
+
+
 /* generic routines for agp>=3 */
 int agp3_generic_fetch_size(void);
 void agp3_generic_tlbflush(struct agp_memory *mem);
index 5a31ec7c62fc40bd8fc213fd5fb69961971d82db..98177a93076f5c7d4f7959b93b37ae0b99617120 100644 (file)
@@ -214,6 +214,7 @@ static struct agp_bridge_driver ali_generic_bridge = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = ali_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 static struct agp_bridge_driver ali_m1541_bridge = {
@@ -237,6 +238,7 @@ static struct agp_bridge_driver ali_m1541_bridge = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = m1541_alloc_page,
        .agp_destroy_page       = m1541_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 
index b4e00a343da9162e559f305794ae31cc99842285..b0acf41c0db9d5f7997783371ac501d55ca89b8f 100644 (file)
@@ -91,6 +91,9 @@ static int alpha_core_agp_insert_memory(struct agp_memory *mem, off_t pg_start,
        int num_entries, status;
        void *temp;
 
+       if (type >= AGP_USER_TYPES || mem->type >= AGP_USER_TYPES)
+               return -EINVAL;
+
        temp = agp_bridge->current_size;
        num_entries = A_SIZE_FIX(temp)->num_entries;
        if ((pg_start + mem->page_count) > num_entries)
@@ -142,6 +145,7 @@ struct agp_bridge_driver alpha_core_agp_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 struct agp_bridge_data *alpha_bridge;
index c85c8cadb6dfd67b9531eb849f140e9095deec9a..3d8d448bf394a181afcd4fc7319b87471aede4a7 100644 (file)
@@ -381,6 +381,7 @@ static struct agp_bridge_driver amd_irongate_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 static struct agp_device_ids amd_agp_device_ids[] __devinitdata =
index 93d2209fee4cfdda3539e0a36a9de177dfffcab2..636d984ed4a62598dc1e11f174f9e9a90262bfee 100644 (file)
@@ -62,12 +62,18 @@ static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
 {
        int i, j, num_entries;
        long long tmp;
+       int mask_type;
+       struct agp_bridge_data *bridge = mem->bridge;
        u32 pte;
 
        num_entries = agp_num_entries();
 
-       if (type != 0 || mem->type != 0)
+       if (type != mem->type)
                return -EINVAL;
+       mask_type = bridge->driver->agp_type_to_mask_type(bridge, type);
+       if (mask_type != 0)
+               return -EINVAL;
+
 
        /* Make sure we can fit the range in the gatt table. */
        /* FIXME: could wrap */
@@ -90,7 +96,7 @@ static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
 
        for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
                tmp = agp_bridge->driver->mask_memory(agp_bridge,
-                       mem->memory[i], mem->type);
+                       mem->memory[i], mask_type);
 
                BUG_ON(tmp & 0xffffff0000000ffcULL);
                pte = (tmp & 0x000000ff00000000ULL) >> 28;
@@ -247,6 +253,7 @@ static struct agp_bridge_driver amd_8151_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 /* Some basic sanity checks for the aperture. */
index 9987dc2e0c3f02474ba75994b9bc7d675e9904db..77c9ad68fba919b09cd72013639622149164d382 100644 (file)
@@ -431,6 +431,7 @@ static struct agp_bridge_driver ati_generic_bridge = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 
index d59e037ddd1234e395b2a277f0c34c45cacb03b1..ebdd6dd66edb6b27931061a3ea732014f58bb31e 100644 (file)
@@ -43,7 +43,7 @@
  * fix some real stupidity. It's only by chance we can bump
  * past 0.99 at all due to some boolean logic error. */
 #define AGPGART_VERSION_MAJOR 0
-#define AGPGART_VERSION_MINOR 101
+#define AGPGART_VERSION_MINOR 102
 static const struct agp_version agp_current_version =
 {
        .major = AGPGART_VERSION_MAJOR,
index 30f730ff81c1717c82eb3f50a8d94a1194255350..658cb1a72d2cf65d9c5244775ecdf1b696313b02 100644 (file)
@@ -335,6 +335,7 @@ static struct agp_bridge_driver efficeon_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 static int __devinit agp_efficeon_probe(struct pci_dev *pdev,
index ee06f382339b584d5014f2cbb2f996b2bb929b59..679d7f972439b43cb511fedf77d334af08928833 100644 (file)
@@ -892,6 +892,9 @@ static int agpioc_allocate_wrap(struct agp_file_private *priv, void __user *arg)
        if (copy_from_user(&alloc, arg, sizeof(struct agp_allocate)))
                return -EFAULT;
 
+       if (alloc.type >= AGP_USER_TYPES)
+               return -EINVAL;
+
        memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type);
 
        if (memory == NULL)
index 3491d6f84bc6098b321965edacf416c7a0d277ac..a627b771c2ebaab0353932b5c642c26ba1235f5b 100644 (file)
@@ -101,6 +101,67 @@ static int agp_get_key(void)
        return -1;
 }
 
+/*
+ * Use kmalloc if possible for the page list. Otherwise fall back to
+ * vmalloc. This speeds things up and also saves memory for small AGP
+ * regions.
+ */
+
+void agp_alloc_page_array(size_t size, struct agp_memory *mem)
+{
+       mem->memory = NULL;
+       mem->vmalloc_flag = 0;
+
+       if (size <= 2*PAGE_SIZE) {
+               mem->memory = kmalloc(size, GFP_KERNEL | __GFP_NORETRY);
+       }
+       if (mem->memory == NULL) {
+               mem->memory = vmalloc(size);
+               mem->vmalloc_flag = 1;
+       }
+}
+EXPORT_SYMBOL(agp_alloc_page_array);
+
+void agp_free_page_array(struct agp_memory *mem)
+{
+       if (mem->vmalloc_flag) {
+               vfree(mem->memory);
+       } else {
+               kfree(mem->memory);
+       }
+}
+EXPORT_SYMBOL(agp_free_page_array);
+
+
+static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages)
+{
+       struct agp_memory *new;
+       unsigned long alloc_size = num_agp_pages*sizeof(struct page *);
+
+       new = kmalloc(sizeof(struct agp_memory), GFP_KERNEL);
+
+       if (new == NULL)
+               return NULL;
+
+       memset(new, 0, sizeof(struct agp_memory));
+       new->key = agp_get_key();
+
+       if (new->key < 0) {
+               kfree(new);
+               return NULL;
+       }
+
+       agp_alloc_page_array(alloc_size, new);
+
+       if (new->memory == NULL) {
+               agp_free_key(new->key);
+               kfree(new);
+               return NULL;
+       }
+       new->num_scratch_pages = 0;
+       return new;
+}
+
 
 struct agp_memory *agp_create_memory(int scratch_pages)
 {
@@ -116,7 +177,8 @@ struct agp_memory *agp_create_memory(int scratch_pages)
                kfree(new);
                return NULL;
        }
-       new->memory = vmalloc(PAGE_SIZE * scratch_pages);
+
+       agp_alloc_page_array(PAGE_SIZE * scratch_pages, new);
 
        if (new->memory == NULL) {
                agp_free_key(new->key);
@@ -124,6 +186,7 @@ struct agp_memory *agp_create_memory(int scratch_pages)
                return NULL;
        }
        new->num_scratch_pages = scratch_pages;
+       new->type = AGP_NORMAL_MEMORY;
        return new;
 }
 EXPORT_SYMBOL(agp_create_memory);
@@ -146,6 +209,11 @@ void agp_free_memory(struct agp_memory *curr)
        if (curr->is_bound == TRUE)
                agp_unbind_memory(curr);
 
+       if (curr->type >= AGP_USER_TYPES) {
+               agp_generic_free_by_type(curr);
+               return;
+       }
+
        if (curr->type != 0) {
                curr->bridge->driver->free_by_type(curr);
                return;
@@ -157,7 +225,7 @@ void agp_free_memory(struct agp_memory *curr)
                flush_agp_mappings();
        }
        agp_free_key(curr->key);
-       vfree(curr->memory);
+       agp_free_page_array(curr);
        kfree(curr);
 }
 EXPORT_SYMBOL(agp_free_memory);
@@ -188,6 +256,13 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge,
        if ((atomic_read(&bridge->current_memory_agp) + page_count) > bridge->max_memory_agp)
                return NULL;
 
+       if (type >= AGP_USER_TYPES) {
+               new = agp_generic_alloc_user(page_count, type);
+               if (new)
+                       new->bridge = bridge;
+               return new;
+       }
+
        if (type != 0) {
                new = bridge->driver->alloc_by_type(page_count, type);
                if (new)
@@ -960,6 +1035,7 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
        off_t j;
        void *temp;
        struct agp_bridge_data *bridge;
+       int mask_type;
 
        bridge = mem->bridge;
        if (!bridge)
@@ -995,7 +1071,12 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
        num_entries -= agp_memory_reserved/PAGE_SIZE;
        if (num_entries < 0) num_entries = 0;
 
-       if (type != 0 || mem->type != 0) {
+       if (type != mem->type) {
+               return -EINVAL;
+       }
+
+       mask_type = bridge->driver->agp_type_to_mask_type(bridge, type);
+       if (mask_type != 0) {
                /* The generic routines know nothing of memory types */
                return -EINVAL;
        }
@@ -1018,7 +1099,8 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
        }
 
        for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-               writel(bridge->driver->mask_memory(bridge, mem->memory[i], mem->type), bridge->gatt_table+j);
+               writel(bridge->driver->mask_memory(bridge, mem->memory[i], mask_type),
+                      bridge->gatt_table+j);
        }
        readl(bridge->gatt_table+j-1);  /* PCI Posting. */
 
@@ -1032,6 +1114,7 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
 {
        size_t i;
        struct agp_bridge_data *bridge;
+       int mask_type;
 
        bridge = mem->bridge;
        if (!bridge)
@@ -1040,7 +1123,11 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
        if (mem->page_count == 0)
                return 0;
 
-       if (type != 0 || mem->type != 0) {
+       if (type != mem->type)
+               return -EINVAL;
+
+       mask_type = bridge->driver->agp_type_to_mask_type(bridge, type);
+       if (mask_type != 0) {
                /* The generic routines know nothing of memory types */
                return -EINVAL;
        }
@@ -1066,12 +1153,34 @@ EXPORT_SYMBOL(agp_generic_alloc_by_type);
 
 void agp_generic_free_by_type(struct agp_memory *curr)
 {
-       vfree(curr->memory);
+       agp_free_page_array(curr);
        agp_free_key(curr->key);
        kfree(curr);
 }
 EXPORT_SYMBOL(agp_generic_free_by_type);
 
+struct agp_memory *agp_generic_alloc_user(size_t page_count, int type)
+{
+       struct agp_memory *new;
+       int i;
+       int pages;
+
+       pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE;
+       new = agp_create_user_memory(page_count);
+       if (new == NULL)
+               return NULL;
+
+       for (i = 0; i < page_count; i++) {
+               new->memory[i] = 0;
+       }
+       new->page_count = 0;
+       new->type = type;
+       new->num_scratch_pages = pages;
+
+       return new;
+}
+EXPORT_SYMBOL(agp_generic_alloc_user);
+
 
 /*
  * Basic Page Allocation Routines -
@@ -1165,6 +1274,15 @@ unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge,
 }
 EXPORT_SYMBOL(agp_generic_mask_memory);
 
+int agp_generic_type_to_mask_type(struct agp_bridge_data *bridge,
+                                 int type)
+{
+       if (type >= AGP_USER_TYPES)
+               return 0;
+       return type;
+}
+EXPORT_SYMBOL(agp_generic_type_to_mask_type);
+
 /*
  * These functions are implemented according to the AGPv3 spec,
  * which covers implementation details that had previously been
index 907fb66ec4a98f12212b181099e39700eb797513..847deabf7f9b6b110f694d68856cb82c7fab9f56 100644 (file)
@@ -438,6 +438,7 @@ struct agp_bridge_driver hp_zx1_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
        .cant_use_aperture      = 1,
 };
 
index 91769443d8fe2d30cf010ef55318a51b43d82e81..3e7618653abd05ca4f74b12788e018251dd88b74 100644 (file)
@@ -293,6 +293,9 @@ static int i460_insert_memory_small_io_page (struct agp_memory *mem,
        pr_debug("i460_insert_memory_small_io_page(mem=%p, pg_start=%ld, type=%d, paddr0=0x%lx)\n",
                 mem, pg_start, type, mem->memory[0]);
 
+       if (type >= AGP_USER_TYPES || mem->type >= AGP_USER_TYPES)
+               return -EINVAL;
+
        io_pg_start = I460_IOPAGES_PER_KPAGE * pg_start;
 
        temp = agp_bridge->current_size;
@@ -396,6 +399,9 @@ static int i460_insert_memory_large_io_page (struct agp_memory *mem,
        struct lp_desc *start, *end, *lp;
        void *temp;
 
+       if (type >= AGP_USER_TYPES || mem->type >= AGP_USER_TYPES)
+               return -EINVAL;
+
        temp = agp_bridge->current_size;
        num_entries = A_SIZE_8(temp)->num_entries;
 
@@ -572,6 +578,7 @@ struct agp_bridge_driver intel_i460_driver = {
 #endif
        .alloc_by_type          = agp_generic_alloc_by_type,
        .free_by_type           = agp_generic_free_by_type,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
        .cant_use_aperture      = 1,
 };
 
index a3011de51f7c049438ae51fae97f3652522cf9a4..4e455f03b4f0bb6426df6aae671c2e676b4beb3a 100644 (file)
@@ -24,6 +24,9 @@
                  agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB)
 
 
+extern int agp_memory_reserved;
+
+
 /* Intel 815 register */
 #define INTEL_815_APCONT       0x51
 #define INTEL_815_ATTBASE_MASK ~0x1FFFFFFF
@@ -68,12 +71,15 @@ static struct aper_size_info_fixed intel_i810_sizes[] =
 
 #define AGP_DCACHE_MEMORY      1
 #define AGP_PHYS_MEMORY                2
+#define INTEL_AGP_CACHED_MEMORY 3
 
 static struct gatt_mask intel_i810_masks[] =
 {
        {.mask = I810_PTE_VALID, .type = 0},
        {.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY},
-       {.mask = I810_PTE_VALID, .type = 0}
+       {.mask = I810_PTE_VALID, .type = 0},
+       {.mask = I810_PTE_VALID | I830_PTE_SYSTEM_CACHED,
+        .type = INTEL_AGP_CACHED_MEMORY}
 };
 
 static struct _intel_i810_private {
@@ -82,6 +88,7 @@ static struct _intel_i810_private {
        int num_dcache_entries;
 } intel_i810_private;
 
+
 static int intel_i810_fetch_size(void)
 {
        u32 smram_miscc;
@@ -201,62 +208,79 @@ static void i8xx_destroy_pages(void *addr)
        atomic_dec(&agp_bridge->current_memory_agp);
 }
 
+static int intel_i830_type_to_mask_type(struct agp_bridge_data *bridge,
+                                       int type)
+{
+       if (type < AGP_USER_TYPES)
+               return type;
+       else if (type == AGP_USER_CACHED_MEMORY)
+               return INTEL_AGP_CACHED_MEMORY;
+       else
+               return 0;
+}
+
 static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
                                int type)
 {
        int i, j, num_entries;
        void *temp;
+       int ret = -EINVAL;
+       int mask_type;
 
        if (mem->page_count == 0)
-               return 0;
+               goto out;
 
        temp = agp_bridge->current_size;
        num_entries = A_SIZE_FIX(temp)->num_entries;
 
        if ((pg_start + mem->page_count) > num_entries)
-               return -EINVAL;
+               goto out_err;
 
-       for (j = pg_start; j < (pg_start + mem->page_count); j++) {
-               if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j)))
-                       return -EBUSY;
-       }
 
-       if (type != 0 || mem->type != 0) {
-               if ((type == AGP_DCACHE_MEMORY) && (mem->type == AGP_DCACHE_MEMORY)) {
-                       /* special insert */
-                       if (!mem->is_flushed) {
-                               global_cache_flush();
-                               mem->is_flushed = TRUE;
-                       }
-
-                       for (i = pg_start; i < (pg_start + mem->page_count); i++) {
-                               writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID, intel_i810_private.registers+I810_PTE_BASE+(i*4));
-                       }
-                       readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4));    /* PCI Posting. */
-
-                       agp_bridge->driver->tlb_flush(mem);
-                       return 0;
+       for (j = pg_start; j < (pg_start + mem->page_count); j++) {
+               if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) {
+                       ret = -EBUSY;
+                       goto out_err;
                }
-               if ((type == AGP_PHYS_MEMORY) && (mem->type == AGP_PHYS_MEMORY))
-                       goto insert;
-               return -EINVAL;
        }
 
-insert:
-       if (!mem->is_flushed) {
-               global_cache_flush();
-               mem->is_flushed = TRUE;
-       }
+       if (type != mem->type)
+               goto out_err;
 
-       for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-               writel(agp_bridge->driver->mask_memory(agp_bridge,
-                       mem->memory[i], mem->type),
-                       intel_i810_private.registers+I810_PTE_BASE+(j*4));
+       mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
+
+       switch (mask_type) {
+       case AGP_DCACHE_MEMORY:
+               if (!mem->is_flushed)
+                       global_cache_flush();
+               for (i = pg_start; i < (pg_start + mem->page_count); i++) {
+                       writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID,
+                              intel_i810_private.registers+I810_PTE_BASE+(i*4));
+               }
+               readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4));
+               break;
+       case AGP_PHYS_MEMORY:
+       case AGP_NORMAL_MEMORY:
+               if (!mem->is_flushed)
+                       global_cache_flush();
+               for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+                       writel(agp_bridge->driver->mask_memory(agp_bridge,
+                                                              mem->memory[i],
+                                                              mask_type),
+                              intel_i810_private.registers+I810_PTE_BASE+(j*4));
+               }
+               readl(intel_i810_private.registers+I810_PTE_BASE+((j-1)*4));
+               break;
+       default:
+               goto out_err;
        }
-       readl(intel_i810_private.registers+I810_PTE_BASE+((j-1)*4));    /* PCI Posting. */
 
        agp_bridge->driver->tlb_flush(mem);
-       return 0;
+out:
+       ret = 0;
+out_err:
+       mem->is_flushed = 1;
+       return ret;
 }
 
 static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start,
@@ -337,12 +361,11 @@ static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
                new->type = AGP_DCACHE_MEMORY;
                new->page_count = pg_count;
                new->num_scratch_pages = 0;
-               vfree(new->memory);
+               agp_free_page_array(new);
                return new;
        }
        if (type == AGP_PHYS_MEMORY)
                return alloc_agpphysmem_i8xx(pg_count, type);
-
        return NULL;
 }
 
@@ -357,7 +380,7 @@ static void intel_i810_free_by_type(struct agp_memory *curr)
                                 gart_to_virt(curr->memory[0]));
                        global_flush_tlb();
                }
-               vfree(curr->memory);
+               agp_free_page_array(curr);
        }
        kfree(curr);
 }
@@ -619,9 +642,11 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int
 {
        int i,j,num_entries;
        void *temp;
+       int ret = -EINVAL;
+       int mask_type;
 
        if (mem->page_count == 0)
-               return 0;
+               goto out;
 
        temp = agp_bridge->current_size;
        num_entries = A_SIZE_FIX(temp)->num_entries;
@@ -631,34 +656,41 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int
                                pg_start,intel_i830_private.gtt_entries);
 
                printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n");
-               return -EINVAL;
+               goto out_err;
        }
 
        if ((pg_start + mem->page_count) > num_entries)
-               return -EINVAL;
+               goto out_err;
 
        /* The i830 can't check the GTT for entries since its read only,
         * depend on the caller to make the correct offset decisions.
         */
 
-       if ((type != 0 && type != AGP_PHYS_MEMORY) ||
-               (mem->type != 0 && mem->type != AGP_PHYS_MEMORY))
-               return -EINVAL;
+       if (type != mem->type)
+               goto out_err;
+
+       mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
 
-       if (!mem->is_flushed) {
+       if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
+           mask_type != INTEL_AGP_CACHED_MEMORY)
+               goto out_err;
+
+       if (!mem->is_flushed)
                global_cache_flush();
-               mem->is_flushed = TRUE;
-       }
 
        for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
                writel(agp_bridge->driver->mask_memory(agp_bridge,
-                       mem->memory[i], mem->type),
-                       intel_i830_private.registers+I810_PTE_BASE+(j*4));
+                                                      mem->memory[i], mask_type),
+                      intel_i830_private.registers+I810_PTE_BASE+(j*4));
        }
        readl(intel_i830_private.registers+I810_PTE_BASE+((j-1)*4));
-
        agp_bridge->driver->tlb_flush(mem);
-       return 0;
+
+out:
+       ret = 0;
+out_err:
+       mem->is_flushed = 1;
+       return ret;
 }
 
 static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start,
@@ -687,7 +719,6 @@ static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type)
 {
        if (type == AGP_PHYS_MEMORY)
                return alloc_agpphysmem_i8xx(pg_count, type);
-
        /* always return NULL for other allocation types for now */
        return NULL;
 }
@@ -734,9 +765,11 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start,
 {
        int i,j,num_entries;
        void *temp;
+       int ret = -EINVAL;
+       int mask_type;
 
        if (mem->page_count == 0)
-               return 0;
+               goto out;
 
        temp = agp_bridge->current_size;
        num_entries = A_SIZE_FIX(temp)->num_entries;
@@ -746,33 +779,41 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start,
                                pg_start,intel_i830_private.gtt_entries);
 
                printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n");
-               return -EINVAL;
+               goto out_err;
        }
 
        if ((pg_start + mem->page_count) > num_entries)
-               return -EINVAL;
+               goto out_err;
 
-       /* The i830 can't check the GTT for entries since its read only,
+       /* The i915 can't check the GTT for entries since its read only,
         * depend on the caller to make the correct offset decisions.
         */
 
-       if ((type != 0 && type != AGP_PHYS_MEMORY) ||
-               (mem->type != 0 && mem->type != AGP_PHYS_MEMORY))
-               return -EINVAL;
+       if (type != mem->type)
+               goto out_err;
+
+       mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
 
-       if (!mem->is_flushed) {
+       if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
+           mask_type != INTEL_AGP_CACHED_MEMORY)
+               goto out_err;
+
+       if (!mem->is_flushed)
                global_cache_flush();
-               mem->is_flushed = TRUE;
-       }
 
        for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
                writel(agp_bridge->driver->mask_memory(agp_bridge,
-                       mem->memory[i], mem->type), intel_i830_private.gtt+j);
+                       mem->memory[i], mask_type), intel_i830_private.gtt+j);
        }
-       readl(intel_i830_private.gtt+j-1);
 
+       readl(intel_i830_private.gtt+j-1);
        agp_bridge->driver->tlb_flush(mem);
-       return 0;
+
+ out:
+       ret = 0;
+ out_err:
+       mem->is_flushed = 1;
+       return ret;
 }
 
 static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start,
@@ -1384,6 +1425,7 @@ static struct agp_bridge_driver intel_generic_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 static struct agp_bridge_driver intel_810_driver = {
@@ -1408,6 +1450,7 @@ static struct agp_bridge_driver intel_810_driver = {
        .free_by_type           = intel_i810_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 static struct agp_bridge_driver intel_815_driver = {
@@ -1431,6 +1474,7 @@ static struct agp_bridge_driver intel_815_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 static struct agp_bridge_driver intel_830_driver = {
@@ -1455,6 +1499,7 @@ static struct agp_bridge_driver intel_830_driver = {
        .free_by_type           = intel_i810_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
 };
 
 static struct agp_bridge_driver intel_820_driver = {
@@ -1478,6 +1523,7 @@ static struct agp_bridge_driver intel_820_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 static struct agp_bridge_driver intel_830mp_driver = {
@@ -1501,6 +1547,7 @@ static struct agp_bridge_driver intel_830mp_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 static struct agp_bridge_driver intel_840_driver = {
@@ -1524,6 +1571,7 @@ static struct agp_bridge_driver intel_840_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 static struct agp_bridge_driver intel_845_driver = {
@@ -1547,6 +1595,7 @@ static struct agp_bridge_driver intel_845_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 static struct agp_bridge_driver intel_850_driver = {
@@ -1570,6 +1619,7 @@ static struct agp_bridge_driver intel_850_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 static struct agp_bridge_driver intel_860_driver = {
@@ -1593,6 +1643,7 @@ static struct agp_bridge_driver intel_860_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 static struct agp_bridge_driver intel_915_driver = {
@@ -1617,6 +1668,7 @@ static struct agp_bridge_driver intel_915_driver = {
        .free_by_type           = intel_i810_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
 };
 
 static struct agp_bridge_driver intel_i965_driver = {
@@ -1641,6 +1693,7 @@ static struct agp_bridge_driver intel_i965_driver = {
        .free_by_type           = intel_i810_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
 };
 
 static struct agp_bridge_driver intel_7505_driver = {
@@ -1664,6 +1717,7 @@ static struct agp_bridge_driver intel_7505_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 static int find_i810(u16 device)
index df7f37b2739abe007a9f9f629f301941f65cadf7..2563286b2fcf3db9a112a986147cd0d23c2c5ed0 100644 (file)
@@ -310,6 +310,7 @@ static struct agp_bridge_driver nvidia_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 static int __devinit agp_nvidia_probe(struct pci_dev *pdev,
index 902648db7efaddb4a526eab1e56b70633bba8d9a..92d1dc45b9be05d53fa04fde3c21c2dae4097488 100644 (file)
@@ -265,6 +265,7 @@ struct agp_bridge_driver sgi_tioca_driver = {
        .free_by_type = agp_generic_free_by_type,
        .agp_alloc_page = sgi_tioca_alloc_page,
        .agp_destroy_page = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
        .cant_use_aperture = 1,
        .needs_scratch_page = 0,
        .num_aperture_sizes = 1,
index 4f2d7d99902f1cfc21ad988846d1176609b3ccf2..9f5ae7714f85e1c8e30e7ff3ae2440f24e5ea91e 100644 (file)
@@ -444,6 +444,7 @@ static struct agp_bridge_driver sworks_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 static int __devinit agp_serverworks_probe(struct pci_dev *pdev,
index dffc19382f7eb828f73426e91b7524f5ffce3305..6c45702e542cc7394ee5596b0d06ef3a2d49047b 100644 (file)
@@ -510,6 +510,7 @@ struct agp_bridge_driver uninorth_agp_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
        .cant_use_aperture      = 1,
 };
 
@@ -534,6 +535,7 @@ struct agp_bridge_driver u3_agp_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
        .cant_use_aperture      = 1,
        .needs_scratch_page     = 1,
 };
index 2ded7a280d7f784eeb0c5ead3a3b55a2e1927c04..2e7c04370cd9e16340ed51da02f38ac30cbce086 100644 (file)
@@ -191,6 +191,7 @@ static struct agp_bridge_driver via_agp3_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 static struct agp_bridge_driver via_driver = {
@@ -214,6 +215,7 @@ static struct agp_bridge_driver via_driver = {
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
 static struct agp_device_ids via_agp_device_ids[] __devinitdata =
index a5c8bb5d80baddd93fd375ce446e27377f60ab8d..abc521cfb08464a7e5a9c3cf11ca60d80f0529af 100644 (file)
@@ -87,10 +87,15 @@ struct agp_memory {
        u32 physical;
        u8 is_bound;
        u8 is_flushed;
+        u8 vmalloc_flag;
 };
 
 #define AGP_NORMAL_MEMORY 0
 
+#define AGP_USER_TYPES (1 << 16)
+#define AGP_USER_MEMORY (AGP_USER_TYPES)
+#define AGP_USER_CACHED_MEMORY (AGP_USER_TYPES + 1)
+
 extern struct agp_bridge_data *agp_bridge;
 extern struct list_head agp_bridges;