summaryrefslogtreecommitdiffstats
path: root/drivers/char/agp/agpgart_be.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/agp/agpgart_be.c')
-rw-r--r--drivers/char/agp/agpgart_be.c321
1 files changed, 258 insertions, 63 deletions
diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c
index ccd53dacc..bf8371676 100644
--- a/drivers/char/agp/agpgart_be.c
+++ b/drivers/char/agp/agpgart_be.c
@@ -32,7 +32,7 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/errno.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/pci.h>
#include <linux/init.h>
@@ -133,45 +133,6 @@ void agp_backend_release(void)
}
/*
- * Basic Page Allocation Routines -
- * These routines handle page allocation
- * and by default they reserve the allocated
- * memory. They also handle incrementing the
- * current_memory_agp value, Which is checked
- * against a maximum value.
- */
-
-static unsigned long agp_alloc_page(void)
-{
- void *pt;
-
- pt = (void *) __get_free_page(GFP_KERNEL);
- if (pt == NULL) {
- return 0;
- }
- atomic_inc(&virt_to_page(pt)->count);
- set_bit(PG_locked, &virt_to_page(pt)->flags);
- atomic_inc(&agp_bridge.current_memory_agp);
- return (unsigned long) pt;
-}
-
-static void agp_destroy_page(unsigned long page)
-{
- void *pt = (void *) page;
-
- if (pt == NULL) {
- return;
- }
- atomic_dec(&virt_to_page(pt)->count);
- clear_bit(PG_locked, &virt_to_page(pt)->flags);
- wake_up(&virt_to_page(pt)->wait);
- free_page((unsigned long) pt);
- atomic_dec(&agp_bridge.current_memory_agp);
-}
-
-/* End Basic Page Allocation Routines */
-
-/*
* Generic routines for handling agp_memory structures -
* They use the basic page allocation routines to do the
* brunt of the work.
@@ -245,7 +206,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_destroy_page((unsigned long)
+ agp_bridge.agp_destroy_page((unsigned long)
phys_to_virt(curr->memory[i]));
}
}
@@ -290,7 +251,7 @@ agp_memory *agp_allocate_memory(size_t page_count, u32 type)
return NULL;
}
for (i = 0; i < page_count; i++) {
- new->memory[i] = agp_alloc_page();
+ new->memory[i] = agp_bridge.agp_alloc_page();
if (new->memory[i] == 0) {
/* Free this structure */
@@ -803,6 +764,45 @@ static void agp_generic_free_by_type(agp_memory * curr)
kfree(curr);
}
+/*
+ * Basic Page Allocation Routines -
+ * These routines handle page allocation
+ * and by default they reserve the allocated
+ * memory. They also handle incrementing the
+ * current_memory_agp value, Which is checked
+ * against a maximum value.
+ */
+
+static unsigned long agp_generic_alloc_page(void)
+{
+ void *pt;
+
+ pt = (void *) __get_free_page(GFP_KERNEL);
+ if (pt == NULL) {
+ return 0;
+ }
+ atomic_inc(&virt_to_page(pt)->count);
+ set_bit(PG_locked, &virt_to_page(pt)->flags);
+ atomic_inc(&agp_bridge.current_memory_agp);
+ return (unsigned long) pt;
+}
+
+static void agp_generic_destroy_page(unsigned long page)
+{
+ void *pt = (void *) page;
+
+ if (pt == NULL) {
+ return;
+ }
+ atomic_dec(&virt_to_page(pt)->count);
+ clear_bit(PG_locked, &virt_to_page(pt)->flags);
+ wake_up(&virt_to_page(pt)->wait);
+ free_page((unsigned long) pt);
+ atomic_dec(&agp_bridge.current_memory_agp);
+}
+
+/* End Basic Page Allocation Routines */
+
void agp_enable(u32 mode)
{
if (agp_bridge.type == NOT_SUPPORTED) return;
@@ -1018,7 +1018,7 @@ static agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
return NULL;
}
MOD_INC_USE_COUNT;
- new->memory[0] = agp_alloc_page();
+ new->memory[0] = agp_bridge.agp_alloc_page();
if (new->memory[0] == 0) {
/* Free this structure */
@@ -1043,7 +1043,7 @@ static void intel_i810_free_by_type(agp_memory * curr)
{
agp_free_key(curr->key);
if(curr->type == AGP_PHYS_MEMORY) {
- agp_destroy_page((unsigned long)
+ agp_bridge.agp_destroy_page((unsigned long)
phys_to_virt(curr->memory[0]));
vfree(curr->memory);
}
@@ -1081,6 +1081,8 @@ static int __init intel_i810_setup(struct pci_dev *i810_dev)
agp_bridge.remove_memory = intel_i810_remove_entries;
agp_bridge.alloc_by_type = intel_i810_alloc_by_type;
agp_bridge.free_by_type = intel_i810_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
return 0;
}
@@ -1271,6 +1273,8 @@ static int __init intel_generic_setup (struct pci_dev *pdev)
agp_bridge.remove_memory = agp_generic_remove_memory;
agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
return 0;
@@ -1299,6 +1303,8 @@ static int __init intel_840_setup (struct pci_dev *pdev)
agp_bridge.remove_memory = agp_generic_remove_memory;
agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
return 0;
@@ -1327,6 +1333,8 @@ static int __init intel_850_setup (struct pci_dev *pdev)
agp_bridge.remove_memory = agp_generic_remove_memory;
agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
return 0;
@@ -1442,6 +1450,8 @@ static int __init via_generic_setup (struct pci_dev *pdev)
agp_bridge.remove_memory = agp_generic_remove_memory;
agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
return 0;
@@ -1551,6 +1561,8 @@ static int __init sis_generic_setup (struct pci_dev *pdev)
agp_bridge.remove_memory = agp_generic_remove_memory;
agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
return 0;
}
@@ -1924,6 +1936,8 @@ static int __init amd_irongate_setup (struct pci_dev *pdev)
agp_bridge.remove_memory = amd_remove_memory;
agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
return 0;
@@ -1961,10 +1975,9 @@ static void ali_tlbflush(agp_memory * mem)
u32 temp;
pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp);
- pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL,
- ((temp & 0xffffff00) | 0x00000090));
- pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL,
- ((temp & 0xffffff00) | 0x00000010));
+// clear tag
+ pci_write_config_dword(agp_bridge.dev, ALI_TAGCTRL,
+ ((temp & 0xfffffff0) | 0x00000001|0x00000002));
}
static void ali_cleanup(void)
@@ -1975,10 +1988,13 @@ static void ali_cleanup(void)
previous_size = A_SIZE_32(agp_bridge.previous_size);
pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp);
- pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL,
- ((temp & 0xffffff00) | 0x00000090));
+// clear tag
+ pci_write_config_dword(agp_bridge.dev, ALI_TAGCTRL,
+ ((temp & 0xffffff00) | 0x00000001|0x00000002));
+
+ pci_read_config_dword(agp_bridge.dev, ALI_ATTBASE, &temp);
pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE,
- previous_size->size_value);
+ ((temp & 0x00000ff0) | previous_size->size_value));
}
static int ali_configure(void)
@@ -1989,17 +2005,62 @@ static int ali_configure(void)
current_size = A_SIZE_32(agp_bridge.current_size);
/* aperture size and gatt addr */
- pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE,
- agp_bridge.gatt_bus_addr | current_size->size_value);
+ pci_read_config_dword(agp_bridge.dev, ALI_ATTBASE, &temp);
+ temp = (((temp & 0x00000ff0) | (agp_bridge.gatt_bus_addr & 0xfffff000))
+ | (current_size->size_value & 0xf));
+ pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE, temp);
/* tlb control */
- pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp);
- pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL,
- ((temp & 0xffffff00) | 0x00000010));
+
+ /*
+ * Question: Jeff, ALi's patch deletes this:
+ *
+ * pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp);
+ * pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL,
+ * ((temp & 0xffffff00) | 0x00000010));
+ *
+ * and replaces it with the following, which seems to duplicate the
+ * next couple of lines below it. I suspect this was an oversight,
+ * but you might want to check up on this?
+ */
+
+ pci_read_config_dword(agp_bridge.dev, ALI_APBASE, &temp);
+ agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
/* address to map to */
pci_read_config_dword(agp_bridge.dev, ALI_APBASE, &temp);
agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+#if 0
+ if (agp_bridge.type == ALI_M1541) {
+ u32 nlvm_addr = 0;
+
+ switch (current_size->size_value) {
+ case 0: break;
+ case 1: nlvm_addr = 0x100000;break;
+ case 2: nlvm_addr = 0x200000;break;
+ case 3: nlvm_addr = 0x400000;break;
+ case 4: nlvm_addr = 0x800000;break;
+ case 6: nlvm_addr = 0x1000000;break;
+ case 7: nlvm_addr = 0x2000000;break;
+ case 8: nlvm_addr = 0x4000000;break;
+ case 9: nlvm_addr = 0x8000000;break;
+ case 10: nlvm_addr = 0x10000000;break;
+ default: break;
+ }
+ nlvm_addr--;
+ nlvm_addr&=0xfff00000;
+
+ nlvm_addr+= agp_bridge.gart_bus_addr;
+ nlvm_addr|=(agp_bridge.gart_bus_addr>>12);
+ printk(KERN_INFO PFX "nlvm top &base = %8x\n",nlvm_addr);
+ }
+#endif
+
+ pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp);
+ temp &= 0xffffff7f; //enable TLB
+ pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL, temp);
+
return 0;
}
@@ -2010,6 +2071,74 @@ static unsigned long ali_mask_memory(unsigned long addr, int type)
return addr | agp_bridge.masks[0].mask;
}
+static void ali_cache_flush(void)
+{
+ global_cache_flush();
+
+ if (agp_bridge.type == ALI_M1541) {
+ int i, page_count;
+ u32 temp;
+
+ page_count = 1 << A_SIZE_32(agp_bridge.current_size)->page_order;
+ for (i = 0; i < PAGE_SIZE * page_count; i += PAGE_SIZE) {
+ 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) |
+ (agp_bridge.gatt_bus_addr + i)) |
+ ALI_CACHE_FLUSH_EN));
+ }
+ }
+}
+
+static unsigned long ali_alloc_page(void)
+{
+ void *pt;
+ u32 temp;
+
+ pt = (void *) __get_free_page(GFP_KERNEL);
+ if (pt == NULL)
+ return 0;
+
+ atomic_inc(&virt_to_page(pt)->count);
+ set_bit(PG_locked, &virt_to_page(pt)->flags);
+ 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((void *)pt)) |
+ ALI_CACHE_FLUSH_EN ));
+ }
+ return (unsigned long) pt;
+}
+
+static void ali_destroy_page(unsigned long page)
+{
+ u32 temp;
+ void *pt = (void *) page;
+
+ if (pt == NULL)
+ return;
+
+ 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((void *)pt)) |
+ ALI_CACHE_FLUSH_EN));
+ }
+
+ atomic_dec(&virt_to_page(pt)->count);
+ clear_bit(PG_locked, &virt_to_page(pt)->flags);
+ wake_up(&virt_to_page(pt)->wait);
+ free_page((unsigned long) pt);
+ atomic_dec(&agp_bridge.current_memory_agp);
+}
/* Setup function */
static gatt_mask ali_generic_masks[] =
@@ -2043,13 +2172,15 @@ static int __init ali_generic_setup (struct pci_dev *pdev)
agp_bridge.tlb_flush = ali_tlbflush;
agp_bridge.mask_memory = ali_mask_memory;
agp_bridge.agp_enable = agp_generic_agp_enable;
- agp_bridge.cache_flush = global_cache_flush;
+ agp_bridge.cache_flush = ali_cache_flush;
agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
agp_bridge.insert_memory = agp_generic_insert_memory;
agp_bridge.remove_memory = agp_generic_remove_memory;
agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = ali_alloc_page;
+ agp_bridge.agp_destroy_page = ali_destroy_page;
return 0;
@@ -2078,6 +2209,42 @@ static struct {
"Ali",
"M1541",
ali_generic_setup },
+ { PCI_DEVICE_ID_AL_M1621_0,
+ PCI_VENDOR_ID_AL,
+ ALI_M1621,
+ "Ali",
+ "M1621",
+ ali_generic_setup },
+ { PCI_DEVICE_ID_AL_M1631_0,
+ PCI_VENDOR_ID_AL,
+ ALI_M1631,
+ "Ali",
+ "M1631",
+ ali_generic_setup },
+ { PCI_DEVICE_ID_AL_M1632_0,
+ PCI_VENDOR_ID_AL,
+ ALI_M1632,
+ "Ali",
+ "M1632",
+ ali_generic_setup },
+ { PCI_DEVICE_ID_AL_M1641_0,
+ PCI_VENDOR_ID_AL,
+ ALI_M1641,
+ "Ali",
+ "M1641",
+ ali_generic_setup },
+ { PCI_DEVICE_ID_AL_M1647_0,
+ PCI_VENDOR_ID_AL,
+ ALI_M1647,
+ "Ali",
+ "M1647",
+ ali_generic_setup },
+ { PCI_DEVICE_ID_AL_M1651_0,
+ PCI_VENDOR_ID_AL,
+ ALI_M1651,
+ "Ali",
+ "M1651",
+ ali_generic_setup },
{ 0,
PCI_VENDOR_ID_AL,
ALI_GENERIC,
@@ -2270,6 +2437,35 @@ static int __init agp_lookup_host_bridge (struct pci_dev *pdev)
while ((i < ARRAY_SIZE (agp_bridge_info)) &&
(agp_bridge_info[i].vendor_id == pdev->vendor)) {
if (pdev->device == agp_bridge_info[i].device_id) {
+#ifdef CONFIG_AGP_ALI
+ if (pdev->device == PCI_DEVICE_ID_AL_M1621_0) {
+ u8 hidden_1621_id;
+
+ pci_read_config_byte(pdev, 0xFB, &hidden_1621_id);
+ switch (hidden_1621_id) {
+ case 0x31:
+ agp_bridge_info[i].chipset_name="M1631";
+ break;
+ case 0x32:
+ agp_bridge_info[i].chipset_name="M1632";
+ break;
+ case 0x41:
+ agp_bridge_info[i].chipset_name="M1641";
+ break;
+ case 0x43:
+ break;
+ case 0x47:
+ agp_bridge_info[i].chipset_name="M1647";
+ break;
+ case 0x51:
+ agp_bridge_info[i].chipset_name="M1651";
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+
printk (KERN_INFO PFX "Detected %s %s chipset\n",
agp_bridge_info[i].vendor_name,
agp_bridge_info[i].chipset_name);
@@ -2375,9 +2571,8 @@ static int __init agp_find_supported_device(void)
if (i810_dev == NULL) {
printk(KERN_ERR PFX "agpgart: Detected an "
"Intel i815, but could not find the"
- " secondary device.\n"
- "Assuming user has added an external AGP"
- " card\n");
+ " secondary device. Assuming a "
+ "non-integrated video card.\n");
break;
}
printk(KERN_INFO PFX "agpgart: Detected an Intel i815 "
@@ -2486,7 +2681,7 @@ static int __init agp_backend_initialize(void)
}
if (agp_bridge.needs_scratch_page == TRUE) {
- agp_bridge.scratch_page = agp_alloc_page();
+ agp_bridge.scratch_page = agp_bridge.agp_alloc_page();
if (agp_bridge.scratch_page == 0) {
printk(KERN_ERR PFX "unable to get memory for "
@@ -2539,7 +2734,7 @@ static int __init agp_backend_initialize(void)
err_out:
if (agp_bridge.needs_scratch_page == TRUE) {
agp_bridge.scratch_page &= ~(0x00000fff);
- agp_destroy_page((unsigned long)
+ agp_bridge.agp_destroy_page((unsigned long)
phys_to_virt(agp_bridge.scratch_page));
}
if (got_gatt)
@@ -2559,7 +2754,7 @@ static void agp_backend_cleanup(void)
if (agp_bridge.needs_scratch_page == TRUE) {
agp_bridge.scratch_page &= ~(0x00000fff);
- agp_destroy_page((unsigned long)
+ agp_bridge.agp_destroy_page((unsigned long)
phys_to_virt(agp_bridge.scratch_page));
}
}