Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/agpgart
[linux-drm-fsl-dcu.git] / drivers / char / agp / intel-agp.c
index d1ede7db5a12f46027174a41ae52c2692b180bf9..06b0bb6d982fca6486a928b98f7e84898a515579 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/kernel.h>
 #include <linux/pagemap.h>
 #include <linux/agp_backend.h>
 #include "agp.h"
@@ -24,6 +25,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 +72,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 {
@@ -117,13 +124,15 @@ static int intel_i810_configure(void)
 
        current_size = A_SIZE_FIX(agp_bridge->current_size);
 
-       pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp);
-       temp &= 0xfff80000;
-
-       intel_i810_private.registers = ioremap(temp, 128 * 4096);
        if (!intel_i810_private.registers) {
-               printk(KERN_ERR PFX "Unable to remap memory.\n");
-               return -ENOMEM;
+               pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp);
+               temp &= 0xfff80000;
+
+               intel_i810_private.registers = ioremap(temp, 128 * 4096);
+               if (!intel_i810_private.registers) {
+                       printk(KERN_ERR PFX "Unable to remap memory.\n");
+                       return -ENOMEM;
+               }
        }
 
        if ((readl(intel_i810_private.registers+I810_DRAM_CTL)
@@ -169,7 +178,7 @@ static void *i8xx_alloc_pages(void)
 {
        struct page * page;
 
-       page = alloc_pages(GFP_KERNEL, 2);
+       page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2);
        if (page == NULL)
                return NULL;
 
@@ -201,52 +210,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)
+               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 (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) {
+                       ret = -EBUSY;
+                       goto out_err;
+               }
        }
 
-       if (type != 0 || mem->type != 0) {
-               if ((type == AGP_DCACHE_MEMORY) && (mem->type == AGP_DCACHE_MEMORY)) {
-                       /* special insert */
+       if (type != mem->type)
+               goto out_err;
+
+       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*4));        /* PCI Posting. */
-                       }
+               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();
-                       agp_bridge->driver->tlb_flush(mem);
-                       return 0;
+               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));
                }
-               if ((type == AGP_PHYS_MEMORY) && (mem->type == AGP_PHYS_MEMORY))
-                       goto insert;
-               return -EINVAL;
-       }
-
-insert:
-       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], mem->type),
-                       intel_i810_private.registers+I810_PTE_BASE+(j*4));
-               readl(intel_i810_private.registers+I810_PTE_BASE+(j*4));        /* PCI Posting. */
+               readl(intel_i810_private.registers+I810_PTE_BASE+((j-1)*4));
+               break;
+       default:
+               goto out_err;
        }
-       global_cache_flush();
 
        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,
@@ -254,12 +290,14 @@ static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start,
 {
        int i;
 
+       if (mem->page_count == 0)
+               return 0;
+
        for (i = pg_start; i < (mem->page_count + pg_start); i++) {
                writel(agp_bridge->scratch_page, intel_i810_private.registers+I810_PTE_BASE+(i*4));
-               readl(intel_i810_private.registers+I810_PTE_BASE+(i*4));        /* PCI Posting. */
        }
+       readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4));
 
-       global_cache_flush();
        agp_bridge->driver->tlb_flush(mem);
        return 0;
 }
@@ -325,12 +363,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;
 }
 
@@ -345,7 +382,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);
 }
@@ -370,6 +407,11 @@ static struct _intel_i830_private {
        struct pci_dev *i830_dev;               /* device one */
        volatile u8 __iomem *registers;
        volatile u32 __iomem *gtt;              /* I915G */
+       /* gtt_entries is the number of gtt entries that are already mapped
+        * to stolen memory.  Stolen memory is larger than the memory mapped
+        * through gtt_entries, as it includes some reserved space for the BIOS
+        * popup and for the GTT.
+        */
        int gtt_entries;
 } intel_i830_private;
 
@@ -380,18 +422,41 @@ static void intel_i830_init_gtt_entries(void)
        u8 rdct;
        int local = 0;
        static const int ddt[4] = { 0, 16, 32, 64 };
-       int size;
+       int size; /* reserved space (in kb) at the top of stolen memory */
 
        pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl);
 
-       /* We obtain the size of the GTT, which is also stored (for some
-        * reason) at the top of stolen memory. Then we add 4KB to that
-        * for the video BIOS popup, which is also stored in there. */
+       if (IS_I965) {
+               u32 pgetbl_ctl;
 
-       if (IS_I965)
-               size = 512 + 4;
-       else
+               pci_read_config_dword(agp_bridge->dev, I810_PGETBL_CTL,
+                                     &pgetbl_ctl);
+               /* The 965 has a field telling us the size of the GTT,
+                * which may be larger than what is necessary to map the
+                * aperture.
+                */
+               switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
+               case I965_PGETBL_SIZE_128KB:
+                       size = 128;
+                       break;
+               case I965_PGETBL_SIZE_256KB:
+                       size = 256;
+                       break;
+               case I965_PGETBL_SIZE_512KB:
+                       size = 512;
+                       break;
+               default:
+                       printk(KERN_INFO PFX "Unknown page table size, "
+                              "assuming 512KB\n");
+                       size = 512;
+               }
+               size += 4; /* add in BIOS popup space */
+       } else {
+               /* On previous hardware, the GTT size was just what was
+                * required to map the aperture.
+                */
                size = agp_bridge->driver->fetch_size() + 4;
+       }
 
        if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
            agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
@@ -579,6 +644,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)
+               goto out;
 
        temp = agp_bridge->current_size;
        num_entries = A_SIZE_FIX(temp)->num_entries;
@@ -588,32 +658,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 (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
+           mask_type != INTEL_AGP_CACHED_MEMORY)
+               goto out_err;
 
-       global_cache_flush();   /* FIXME: Necessary ?*/
+       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], mem->type),
-                       intel_i830_private.registers+I810_PTE_BASE+(j*4));
-               readl(intel_i830_private.registers+I810_PTE_BASE+(j*4));        /* PCI Posting. */
+                                                      mem->memory[i], mask_type),
+                      intel_i830_private.registers+I810_PTE_BASE+(j*4));
        }
-
-       global_cache_flush();
+       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,
@@ -621,7 +700,8 @@ static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start,
 {
        int i;
 
-       global_cache_flush();
+       if (mem->page_count == 0)
+               return 0;
 
        if (pg_start < intel_i830_private.gtt_entries) {
                printk (KERN_INFO PFX "Trying to disable local/stolen memory\n");
@@ -630,10 +710,9 @@ static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start,
 
        for (i = pg_start; i < (mem->page_count + pg_start); i++) {
                writel(agp_bridge->scratch_page, intel_i830_private.registers+I810_PTE_BASE+(i*4));
-               readl(intel_i830_private.registers+I810_PTE_BASE+(i*4));        /* PCI Posting. */
        }
+       readl(intel_i830_private.registers+I810_PTE_BASE+((i-1)*4));
 
-       global_cache_flush();
        agp_bridge->driver->tlb_flush(mem);
        return 0;
 }
@@ -642,7 +721,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;
 }
@@ -689,6 +767,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)
+               goto out;
 
        temp = agp_bridge->current_size;
        num_entries = A_SIZE_FIX(temp)->num_entries;
@@ -698,31 +781,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;
 
-       global_cache_flush();
+       mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
+
+       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();
 
        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);
-               readl(intel_i830_private.gtt+j);        /* PCI Posting. */
+                       mem->memory[i], mask_type), intel_i830_private.gtt+j);
        }
 
-       global_cache_flush();
+       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,
@@ -730,7 +823,8 @@ static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start,
 {
        int i;
 
-       global_cache_flush();
+       if (mem->page_count == 0)
+               return 0;
 
        if (pg_start < intel_i830_private.gtt_entries) {
                printk (KERN_INFO PFX "Trying to disable local/stolen memory\n");
@@ -739,30 +833,34 @@ static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start,
 
        for (i = pg_start; i < (mem->page_count + pg_start); i++) {
                writel(agp_bridge->scratch_page, intel_i830_private.gtt+i);
-               readl(intel_i830_private.gtt+i);
        }
+       readl(intel_i830_private.gtt+i-1);
 
-       global_cache_flush();
        agp_bridge->driver->tlb_flush(mem);
        return 0;
 }
 
-static int intel_i915_fetch_size(void)
+/* Return the aperture size by just checking the resource length.  The effect
+ * described in the spec of the MSAC registers is just changing of the
+ * resource size.
+ */
+static int intel_i9xx_fetch_size(void)
 {
-       struct aper_size_info_fixed *values;
-       u32 temp, offset;
+       int num_sizes = ARRAY_SIZE(intel_i830_sizes);
+       int aper_size; /* size in megabytes */
+       int i;
 
-#define I915_256MB_ADDRESS_MASK (1<<27)
+       aper_size = pci_resource_len(intel_i830_private.i830_dev, 2) / MB(1);
 
-       values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
+       for (i = 0; i < num_sizes; i++) {
+               if (aper_size == intel_i830_sizes[i].size) {
+                       agp_bridge->current_size = intel_i830_sizes + i;
+                       agp_bridge->previous_size = agp_bridge->current_size;
+                       return aper_size;
+               }
+       }
 
-       pci_read_config_dword(intel_i830_private.i830_dev, I915_GMADDR, &temp);
-       if (temp & I915_256MB_ADDRESS_MASK)
-               offset = 0;     /* 128MB aperture */
-       else
-               offset = 2;     /* 256MB aperture */
-       agp_bridge->previous_size = agp_bridge->current_size = (void *)(values + offset);
-       return values[offset].size;
+       return 0;
 }
 
 /* The intel i915 automatically initializes the agp aperture during POST.
@@ -805,39 +903,29 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
 
        return 0;
 }
-static int intel_i965_fetch_size(void)
-{
-       struct aper_size_info_fixed *values;
-       u32 offset = 0;
-       u8 temp;
-
-#define I965_512MB_ADDRESS_MASK (3<<1)
-
-       values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
-
-       pci_read_config_byte(intel_i830_private.i830_dev, I965_MSAC, &temp);
-       temp &= I965_512MB_ADDRESS_MASK;
-       switch (temp) {
-       case 0x00:
-               offset = 0; /* 128MB */
-               break;
-       case 0x06:
-               offset = 3; /* 512MB */
-               break;
-       default:
-       case 0x02:
-               offset = 2; /* 256MB */
-               break;
-       }
-
-       agp_bridge->previous_size = agp_bridge->current_size = (void *)(values + offset);
-
-       return values[offset].size;
+
+/*
+ * The i965 supports 36-bit physical addresses, but to keep
+ * the format of the GTT the same, the bits that don't fit
+ * in a 32-bit word are shifted down to bits 4..7.
+ *
+ * Gcc is smart enough to notice that "(addr >> 28) & 0xf0"
+ * is always zero on 32-bit architectures, so no need to make
+ * this conditional.
+ */
+static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
+       unsigned long addr, int type)
+{
+       /* Shift high bits down */
+       addr |= (addr >> 28) & 0xf0;
+
+       /* Type checking must be done elsewhere */
+       return addr | bridge->driver->masks[type].mask;
 }
 
 /* The intel i965 automatically initializes the agp aperture during POST.
-+ * Use the memory already set aside for in the GTT.
-+ */
+ * Use the memory already set aside for in the GTT.
+ */
 static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
 {
        int page_order;
@@ -1339,6 +1427,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 = {
@@ -1363,6 +1452,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 = {
@@ -1386,6 +1476,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 = {
@@ -1410,6 +1501,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 = {
@@ -1433,6 +1525,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 = {
@@ -1456,6 +1549,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 = {
@@ -1479,6 +1573,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 = {
@@ -1502,6 +1597,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 = {
@@ -1525,6 +1621,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 = {
@@ -1548,6 +1645,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 = {
@@ -1557,7 +1655,7 @@ static struct agp_bridge_driver intel_915_driver = {
        .num_aperture_sizes     = 4,
        .needs_scratch_page     = TRUE,
        .configure              = intel_i915_configure,
-       .fetch_size             = intel_i915_fetch_size,
+       .fetch_size             = intel_i9xx_fetch_size,
        .cleanup                = intel_i915_cleanup,
        .tlb_flush              = intel_i810_tlbflush,
        .mask_memory            = intel_i810_mask_memory,
@@ -1572,6 +1670,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 = {
@@ -1581,10 +1680,10 @@ static struct agp_bridge_driver intel_i965_driver = {
        .num_aperture_sizes     = 4,
        .needs_scratch_page     = TRUE,
        .configure              = intel_i915_configure,
-       .fetch_size             = intel_i965_fetch_size,
+       .fetch_size             = intel_i9xx_fetch_size,
        .cleanup                = intel_i915_cleanup,
        .tlb_flush              = intel_i810_tlbflush,
-       .mask_memory            = intel_i810_mask_memory,
+       .mask_memory            = intel_i965_mask_memory,
        .masks                  = intel_i810_masks,
        .agp_enable             = intel_i810_agp_enable,
        .cache_flush            = global_cache_flush,
@@ -1596,6 +1695,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 = {
@@ -1619,6 +1719,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)
@@ -1910,6 +2011,15 @@ static int agp_intel_resume(struct pci_dev *pdev)
 
        pci_restore_state(pdev);
 
+       /* We should restore our graphics device's config space,
+        * as host bridge (00:00) resumes before graphics device (02:00),
+        * then our access to its pci space can work right.
+        */
+       if (intel_i810_private.i810_dev)
+               pci_restore_state(intel_i810_private.i810_dev);
+       if (intel_i830_private.i830_dev)
+               pci_restore_state(intel_i830_private.i830_dev);
+
        if (bridge->driver == &intel_generic_driver)
                intel_configure();
        else if (bridge->driver == &intel_850_driver)