agp: Add generic support for graphics dma remapping
New driver hooks for support graphics memory dma remapping
are introduced in this patch. It makes generic code can
tell if current device needs dma remapping, then call driver
provided interfaces for mapping and unmapping. Change has
also been made to handle scratch_page in remapping case.
Signed-off-by: Zhenyu Wang <zhenyu.z.wang@intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index ce110a3..17e6d0d 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -121,6 +121,11 @@
void (*agp_destroy_pages)(struct agp_memory *);
int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
void (*chipset_flush)(struct agp_bridge_data *);
+
+ int (*agp_map_page)(void *addr, dma_addr_t *ret);
+ void (*agp_unmap_page)(void *addr, dma_addr_t dma);
+ int (*agp_map_memory)(struct agp_memory *mem);
+ void (*agp_unmap_memory)(struct agp_memory *mem);
};
struct agp_bridge_data {
@@ -135,6 +140,7 @@
u32 *gatt_table_real;
unsigned long scratch_page;
unsigned long scratch_page_real;
+ dma_addr_t scratch_page_dma;
unsigned long gart_bus_addr;
unsigned long gatt_bus_addr;
u32 mode;
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index 3bd7e50..19ac366 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -152,6 +152,15 @@
bridge->scratch_page_real = phys_to_gart(page_to_phys(page));
bridge->scratch_page = bridge->driver->mask_memory(bridge,
phys_to_gart(page_to_phys(page)), 0);
+
+ if (bridge->driver->agp_map_page &&
+ bridge->driver->agp_map_page(phys_to_virt(page_to_phys(page)),
+ &bridge->scratch_page_dma)) {
+ dev_err(&bridge->dev->dev,
+ "unable to dma-map scratch page\n");
+ rc = -ENOMEM;
+ goto err_out_nounmap;
+ }
}
size_value = bridge->driver->fetch_size();
@@ -191,6 +200,13 @@
return 0;
err_out:
+ if (bridge->driver->needs_scratch_page &&
+ bridge->driver->agp_unmap_page) {
+ void *va = gart_to_virt(bridge->scratch_page_real);
+
+ bridge->driver->agp_unmap_page(va, bridge->scratch_page_dma);
+ }
+err_out_nounmap:
if (bridge->driver->needs_scratch_page) {
void *va = gart_to_virt(bridge->scratch_page_real);
@@ -221,6 +237,10 @@
bridge->driver->needs_scratch_page) {
void *va = gart_to_virt(bridge->scratch_page_real);
+ if (bridge->driver->agp_unmap_page)
+ bridge->driver->agp_unmap_page(va,
+ bridge->scratch_page_dma);
+
bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP);
bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE);
}
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index a3bcc7e..28f0208 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -437,6 +437,12 @@
curr->bridge->driver->cache_flush();
curr->is_flushed = true;
}
+
+ if (curr->bridge->driver->agp_map_memory) {
+ ret_val = curr->bridge->driver->agp_map_memory(curr);
+ if (ret_val)
+ return ret_val;
+ }
ret_val = curr->bridge->driver->insert_memory(curr, pg_start, curr->type);
if (ret_val != 0)
@@ -478,6 +484,9 @@
if (ret_val != 0)
return ret_val;
+ if (curr->bridge->driver->agp_unmap_memory)
+ curr->bridge->driver->agp_unmap_memory(curr);
+
curr->is_bound = false;
curr->pg_start = 0;
spin_lock(&curr->bridge->mapped_lock);
diff --git a/include/linux/agp_backend.h b/include/linux/agp_backend.h
index 76fa794..8a294d6 100644
--- a/include/linux/agp_backend.h
+++ b/include/linux/agp_backend.h
@@ -79,9 +79,13 @@
u32 physical;
bool is_bound;
bool is_flushed;
- bool vmalloc_flag;
+ bool vmalloc_flag;
+ bool sg_vmalloc_flag;
/* list of agp_memory mapped to the aperture */
struct list_head mapped_list;
+ /* DMA-mapped addresses */
+ struct scatterlist *sg_list;
+ int num_sg;
};
#define AGP_NORMAL_MEMORY 0