[AGPGART] fix detection of aperture size versus GTT size on G965
authorEric Anholt <eric@anholt.net>
Tue, 19 Dec 2006 20:57:24 +0000 (12:57 -0800)
committerDave Jones <davej@redhat.com>
Sat, 23 Dec 2006 04:12:22 +0000 (23:12 -0500)
On the G965, the GTT size may be larger than is required to cover the
aperture.  (In fact, on all hardware we've seen, the GTT is 512KB to the
aperture's 256MB).  A previous commit forced the aperture size to 512MB on
G965 to match GTT, which would likely result in hangs at best if users
tried to rely on agpgart's aperture size information.  Instead, we use the
resource length for the aperture size and the system's reported GTT size
when available for the GTT size.

Because the MSAC registers which had been read for aperture size detection
on i9xx chips just cause a change in the resource size, we can use generic
code for aperture detection on all i9xx.

Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Dave Jones <davej@redhat.com>
drivers/char/agp/agp.h
drivers/char/agp/intel-agp.c

index 8b3317f..1d59e2a 100644 (file)
@@ -225,6 +225,10 @@ struct agp_bridge_data {
 #define I810_GMS_DISABLE       0x00000000
 #define I810_PGETBL_CTL                0x2020
 #define I810_PGETBL_ENABLED    0x00000001
+#define I965_PGETBL_SIZE_MASK  0x0000000e
+#define I965_PGETBL_SIZE_512KB (0 << 1)
+#define I965_PGETBL_SIZE_256KB (1 << 1)
+#define I965_PGETBL_SIZE_128KB (2 << 1)
 #define I810_DRAM_CTL          0x3000
 #define I810_DRAM_ROW_0                0x00000001
 #define I810_DRAM_ROW_0_SDRAM  0x00000001
index 029d7f6..ccb8018 100644 (file)
@@ -382,6 +382,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;
 
@@ -392,14 +397,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. */
-       size = agp_bridge->driver->fetch_size() + 4;
+       if (IS_I965) {
+               u32 pgetbl_ctl;
+
+               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) {
@@ -765,22 +797,27 @@ static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start,
        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 = sizeof(intel_i830_sizes) / sizeof(*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.
@@ -843,40 +880,9 @@ static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
        return addr | bridge->driver->masks[type].mask;
 }
 
-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);
-
-       /* The i965 GTT is always sized as if it had a 512kB aperture size */
-       return 512;
-}
-
 /* 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;
@@ -1596,7 +1602,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,
@@ -1620,7 +1626,7 @@ 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_i965_mask_memory,