aboutsummaryrefslogtreecommitdiff
path: root/drivers/char/agp/intel-agp.c
diff options
context:
space:
mode:
authorThomas Hellstrom <thomas@tungstengraphics.com>2007-01-23 10:33:43 +0100
committerDave Jones <davej@redhat.com>2007-02-03 17:16:24 -0500
commita030ce4477baa06dd9c037ccd3c8d171aac9ed44 (patch)
tree1961f175a2785cc7d5325f45139558de471c4733 /drivers/char/agp/intel-agp.c
parent0316fe8319ff62e527d0d91a3bc7df1c59eafae8 (diff)
[AGPGART] Allow drm-populated agp memory types
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>
Diffstat (limited to 'drivers/char/agp/intel-agp.c')
-rw-r--r--drivers/char/agp/intel-agp.c186
1 files changed, 120 insertions, 66 deletions
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index a3011de51f7..4e455f03b4f 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -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)