summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.transmeta.com>2002-06-17 19:45:51 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2002-06-17 19:45:51 -0700
commit1dbe77d331a291da35915e5b6a87087ae7bf0b1b (patch)
tree66ac01932ac979c2ae667d82b50cc283b6b1785f /drivers
parent68d6275b42055147e1e885e87424ee61dffa34e8 (diff)
parentc8712aebdb2455a095d596c1a5a6af358b3efde3 (diff)
Merge
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/agp/agp.h4
-rw-r--r--drivers/char/agp/agpgart_be.c155
2 files changed, 60 insertions, 99 deletions
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index be8178161e80..94e405104df4 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -118,8 +118,8 @@ struct agp_bridge_data {
int (*remove_memory) (agp_memory *, off_t, int);
agp_memory *(*alloc_by_type) (size_t, int);
void (*free_by_type) (agp_memory *);
- unsigned long (*agp_alloc_page) (void);
- void (*agp_destroy_page) (unsigned long);
+ void *(*agp_alloc_page) (void);
+ void (*agp_destroy_page) (void *);
int (*suspend)(void);
void (*resume)(void);
diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c
index 44cbc013d91c..8ba761695215 100644
--- a/drivers/char/agp/agpgart_be.c
+++ b/drivers/char/agp/agpgart_be.c
@@ -22,6 +22,8 @@
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
+ * TODO:
+ * - Allocate more than order 0 pages to avoid too much linear map splitting.
*/
#include <linux/config.h>
#include <linux/version.h>
@@ -43,6 +45,7 @@
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/page.h>
+#include <asm/agp.h>
#include <linux/agp_backend.h>
#include "agp.h"
@@ -59,56 +62,28 @@ EXPORT_SYMBOL(agp_enable);
EXPORT_SYMBOL(agp_backend_acquire);
EXPORT_SYMBOL(agp_backend_release);
-static void flush_cache(void);
-
static struct agp_bridge_data agp_bridge;
static int agp_try_unsupported __initdata = 0;
-
-static inline void flush_cache(void)
-{
-#if defined(__i386__) || defined(__x86_64__)
- asm volatile ("wbinvd":::"memory");
-#elif defined(__alpha__) || defined(__ia64__) || defined(__sparc__)
- /* ??? I wonder if we'll really need to flush caches, or if the
- core logic can manage to keep the system coherent. The ARM
- speaks only of using `cflush' to get things in memory in
- preparation for power failure.
-
- If we do need to call `cflush', we'll need a target page,
- as we can only flush one page at a time.
-
- Ditto for IA-64. --davidm 00/08/07 */
- mb();
-#else
-#error "Please define flush_cache."
-#endif
-}
-
#ifdef CONFIG_SMP
-static atomic_t cpus_waiting;
-
static void ipi_handler(void *null)
{
- flush_cache();
- atomic_dec(&cpus_waiting);
- while (atomic_read(&cpus_waiting) > 0)
- barrier();
+ flush_agp_cache();
}
static void smp_flush_cache(void)
{
- atomic_set(&cpus_waiting, num_online_cpus() - 1);
- if (smp_call_function(ipi_handler, NULL, 1, 0) != 0)
+ if (smp_call_function(ipi_handler, NULL, 1, 1) != 0)
panic(PFX "timed out waiting for the other CPUs!\n");
- flush_cache();
- while (atomic_read(&cpus_waiting) > 0)
- barrier();
+ flush_agp_cache();
}
#define global_cache_flush smp_flush_cache
#else /* CONFIG_SMP */
-#define global_cache_flush flush_cache
-#endif /* CONFIG_SMP */
+static void global_cache_flush(void)
+{
+ flush_agp_cache();
+}
+#endif /* !CONFIG_SMP */
int agp_backend_acquire(void)
{
@@ -208,8 +183,7 @@ void agp_free_memory(agp_memory * curr)
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]));
+ agp_bridge.agp_destroy_page(phys_to_virt(curr->memory[i]));
}
}
agp_free_key(curr->key);
@@ -252,21 +226,22 @@ agp_memory *agp_allocate_memory(size_t page_count, u32 type)
MOD_DEC_USE_COUNT;
return NULL;
}
+
for (i = 0; i < page_count; i++) {
- new->memory[i] = agp_bridge.agp_alloc_page();
+ void *addr = agp_bridge.agp_alloc_page();
- if (new->memory[i] == 0) {
+ if (addr == NULL) {
/* Free this structure */
agp_free_memory(new);
return NULL;
}
new->memory[i] =
- agp_bridge.mask_memory(
- virt_to_phys((void *) new->memory[i]),
- type);
+ agp_bridge.mask_memory(virt_to_phys(addr), type);
new->page_count++;
}
+ flush_agp_mappings();
+
return new;
}
@@ -561,6 +536,7 @@ static int agp_generic_create_gatt_table(void)
agp_bridge.current_size;
break;
}
+ temp = agp_bridge.current_size;
} else {
agp_bridge.aperture_size_idx = i;
}
@@ -761,7 +737,7 @@ static void agp_generic_free_by_type(agp_memory * curr)
* against a maximum value.
*/
-static unsigned long agp_generic_alloc_page(void)
+static void *agp_generic_alloc_page(void)
{
struct page * page;
@@ -769,24 +745,26 @@ static unsigned long agp_generic_alloc_page(void)
if (page == NULL)
return 0;
+ map_page_into_agp(page);
+
get_page(page);
SetPageLocked(page);
atomic_inc(&agp_bridge.current_memory_agp);
- return (unsigned long)page_address(page);
+ return page_address(page);
}
-static void agp_generic_destroy_page(unsigned long addr)
+static void agp_generic_destroy_page(void *addr)
{
- void *pt = (void *) addr;
struct page *page;
- if (pt == NULL)
+ if (addr == NULL)
return;
- page = virt_to_page(pt);
+ page = virt_to_page(addr);
+ unmap_page_from_agp(page);
put_page(page);
unlock_page(page);
- free_page((unsigned long) pt);
+ free_page((unsigned long)addr);
atomic_dec(&agp_bridge.current_memory_agp);
}
@@ -993,6 +971,7 @@ static agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
return new;
}
if(type == AGP_PHYS_MEMORY) {
+ void *addr;
/* The I810 requires a physical address to program
* it's mouse pointer into hardware. However the
* Xserver still writes to it through the agp
@@ -1007,17 +986,14 @@ static agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
return NULL;
}
MOD_INC_USE_COUNT;
- new->memory[0] = agp_bridge.agp_alloc_page();
+ addr = agp_bridge.agp_alloc_page();
- if (new->memory[0] == 0) {
+ if (addr == NULL) {
/* Free this structure */
agp_free_memory(new);
return NULL;
}
- new->memory[0] =
- agp_bridge.mask_memory(
- virt_to_phys((void *) new->memory[0]),
- type);
+ new->memory[0] = agp_bridge.mask_memory(virt_to_phys(addr), type);
new->page_count = 1;
new->num_scratch_pages = 1;
new->type = AGP_PHYS_MEMORY;
@@ -1032,7 +1008,7 @@ static void intel_i810_free_by_type(agp_memory * curr)
{
agp_free_key(curr->key);
if(curr->type == AGP_PHYS_MEMORY) {
- agp_bridge.agp_destroy_page((unsigned long)
+ agp_bridge.agp_destroy_page(
phys_to_virt(curr->memory[0]));
vfree(curr->memory);
}
@@ -1291,7 +1267,7 @@ static agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type)
if (type == AGP_DCACHE_MEMORY) return(NULL);
if (type == AGP_PHYS_MEMORY) {
- unsigned long physical;
+ void *addr;
/* The i830 requires a physical address to program
* it's mouse pointer into hardware. However the
@@ -1306,19 +1282,18 @@ static agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type)
if (nw == NULL) return(NULL);
MOD_INC_USE_COUNT;
- nw->memory[0] = agp_bridge.agp_alloc_page();
- physical = nw->memory[0];
- if (nw->memory[0] == 0) {
+ addr = agp_bridge.agp_alloc_page();
+ if (addr == NULL) {
/* free this structure */
agp_free_memory(nw);
return(NULL);
}
- nw->memory[0] = agp_bridge.mask_memory(virt_to_phys((void *) nw->memory[0]),type);
+ nw->memory[0] = agp_bridge.mask_memory(virt_to_phys(addr),type);
nw->page_count = 1;
nw->num_scratch_pages = 1;
nw->type = AGP_PHYS_MEMORY;
- nw->physical = virt_to_phys((void *) physical);
+ nw->physical = virt_to_phys(addr);
return(nw);
}
@@ -1849,16 +1824,17 @@ static int intel_i460_remove_memory(agp_memory * mem, off_t pg_start, int type)
* Let's just hope nobody counts on the allocated AGP memory being there
* before bind time (I don't think current drivers do)...
*/
-static unsigned long intel_i460_alloc_page(void)
+static void * intel_i460_alloc_page(void)
{
if (intel_i460_cpk)
return agp_generic_alloc_page();
/* Returning NULL would cause problems */
- return ~0UL;
+ /* AK: really dubious code. */
+ return (void *)~0UL;
}
-static void intel_i460_destroy_page(unsigned long page)
+static void intel_i460_destroy_page(void *page)
{
if (intel_i460_cpk)
agp_generic_destroy_page(page);
@@ -3298,38 +3274,29 @@ static void ali_cache_flush(void)
}
}
-static unsigned long ali_alloc_page(void)
+static void *ali_alloc_page(void)
{
- struct page *page;
- u32 temp;
+ void *adr = agp_generic_alloc_page();
+ unsigned temp;
- page = alloc_page(GFP_KERNEL);
- if (page == NULL)
+ if (adr == 0)
return 0;
- get_page(page);
- SetPageLocked(page);
- atomic_inc(&agp_bridge.current_memory_agp);
-
- global_cache_flush();
-
if (agp_bridge.type == ALI_M1541) {
pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp);
pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL,
(((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
- virt_to_phys(page_address(page))) |
+ virt_to_phys(adr)) |
ALI_CACHE_FLUSH_EN ));
}
- return (unsigned long)page_address(page);
+ return adr;
}
-static void ali_destroy_page(unsigned long addr)
+static void ali_destroy_page(void * addr)
{
u32 temp;
- void *pt = (void *) addr;
- struct page *page;
- if (pt == NULL)
+ if (addr == NULL)
return;
global_cache_flush();
@@ -3338,15 +3305,11 @@ static void ali_destroy_page(unsigned long addr)
pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp);
pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL,
(((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
- virt_to_phys((void *)pt)) |
+ virt_to_phys(addr)) |
ALI_CACHE_FLUSH_EN));
}
- page = virt_to_page(pt);
- put_page(page);
- unlock_page(page);
- free_page((unsigned long) pt);
- atomic_dec(&agp_bridge.current_memory_agp);
+ agp_generic_destroy_page(addr);
}
/* Setup function */
@@ -5011,15 +4974,15 @@ static int __init agp_backend_initialize(void)
}
if (agp_bridge.needs_scratch_page == TRUE) {
- agp_bridge.scratch_page = agp_bridge.agp_alloc_page();
+ void *addr;
+ addr = agp_bridge.agp_alloc_page();
- if (agp_bridge.scratch_page == 0) {
+ if (addr == NULL) {
printk(KERN_ERR PFX "unable to get memory for "
"scratch page.\n");
return -ENOMEM;
}
- agp_bridge.scratch_page =
- virt_to_phys((void *) agp_bridge.scratch_page);
+ agp_bridge.scratch_page = virt_to_phys(addr);
agp_bridge.scratch_page =
agp_bridge.mask_memory(agp_bridge.scratch_page, 0);
}
@@ -5064,8 +5027,7 @@ static int __init agp_backend_initialize(void)
err_out:
if (agp_bridge.needs_scratch_page == TRUE) {
agp_bridge.scratch_page &= ~(0x00000fff);
- agp_bridge.agp_destroy_page((unsigned long)
- phys_to_virt(agp_bridge.scratch_page));
+ agp_bridge.agp_destroy_page(phys_to_virt(agp_bridge.scratch_page));
}
if (got_gatt)
agp_bridge.free_gatt_table();
@@ -5084,8 +5046,7 @@ static void agp_backend_cleanup(void)
if (agp_bridge.needs_scratch_page == TRUE) {
agp_bridge.scratch_page &= ~(0x00000fff);
- agp_bridge.agp_destroy_page((unsigned long)
- phys_to_virt(agp_bridge.scratch_page));
+ agp_bridge.agp_destroy_page(phys_to_virt(agp_bridge.scratch_page));
}
}