Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/agpgart
authorLinus Torvalds <torvalds@woody.osdl.org>
Thu, 4 Jan 2007 01:34:54 +0000 (17:34 -0800)
committerLinus Torvalds <torvalds@woody.osdl.org>
Thu, 4 Jan 2007 01:34:54 +0000 (17:34 -0800)
* master.kernel.org:/pub/scm/linux/kernel/git/davej/agpgart:
  [AGPGART] drivers/char/agp/sgi-agp.c: check kmalloc() return value
  [AGPGART] Fix PCI-posting flush typo.
  [AGPGART] fix detection of aperture size versus GTT size on G965
  [AGPGART] Remove unnecessary flushes when inserting and removing pages.
  [AGPGART] K8M890 support for amd-k8.

drivers/char/agp/agp.h
drivers/char/agp/amd64-agp.c
drivers/char/agp/generic.c
drivers/char/agp/intel-agp.c
drivers/char/agp/sgi-agp.c
include/linux/pci_ids.h

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 2f2c4ef..9793004 100644 (file)
@@ -650,6 +650,15 @@ static struct pci_device_id agp_amd64_pci_table[] = {
        .subvendor      = PCI_ANY_ID,
        .subdevice      = PCI_ANY_ID,
        },
+       /* VIA K8M890 / K8N890 */
+       {
+       .class          = (PCI_CLASS_BRIDGE_HOST << 8),
+       .class_mask     = ~0,
+       .vendor         = PCI_VENDOR_ID_VIA,
+       .device         = PCI_DEVICE_ID_VIA_K8M890CE,
+       .subvendor      = PCI_ANY_ID,
+       .subdevice      = PCI_ANY_ID,
+       },
        /* VIA K8T890 */
        {
        .class          = (PCI_CLASS_BRIDGE_HOST << 8),
index 883a36a..3491d6f 100644 (file)
@@ -965,6 +965,9 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
        if (!bridge)
                return -EINVAL;
 
+       if (mem->page_count == 0)
+               return 0;
+
        temp = bridge->current_size;
 
        switch (bridge->driver->size_type) {
@@ -1016,8 +1019,8 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
 
        for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
                writel(bridge->driver->mask_memory(bridge, mem->memory[i], mem->type), bridge->gatt_table+j);
-               readl(bridge->gatt_table+j);    /* PCI Posting. */
        }
+       readl(bridge->gatt_table+j-1);  /* PCI Posting. */
 
        bridge->driver->tlb_flush(mem);
        return 0;
@@ -1034,6 +1037,9 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
        if (!bridge)
                return -EINVAL;
 
+       if (mem->page_count == 0)
+               return 0;
+
        if (type != 0 || mem->type != 0) {
                /* The generic routines know nothing of memory types */
                return -EINVAL;
@@ -1042,10 +1048,9 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
        /* AK: bogus, should encode addresses > 4GB */
        for (i = pg_start; i < (mem->page_count + pg_start); i++) {
                writel(bridge->scratch_page, bridge->gatt_table+i);
-               readl(bridge->gatt_table+i);    /* PCI Posting. */
        }
+       readl(bridge->gatt_table+i-1);  /* PCI Posting. */
 
-       global_cache_flush();
        bridge->driver->tlb_flush(mem);
        return 0;
 }
index 555b3a8..ab0a9c0 100644 (file)
@@ -207,6 +207,9 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
        int i, j, num_entries;
        void *temp;
 
+       if (mem->page_count == 0)
+               return 0;
+
        temp = agp_bridge->current_size;
        num_entries = A_SIZE_FIX(temp)->num_entries;
 
@@ -221,12 +224,16 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
        if (type != 0 || mem->type != 0) {
                if ((type == AGP_DCACHE_MEMORY) && (mem->type == AGP_DCACHE_MEMORY)) {
                        /* special insert */
-                       global_cache_flush();
+                       if (!mem->is_flushed) {
+                               global_cache_flush();
+                               mem->is_flushed = TRUE;
+                       }
+
                        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. */
                        }
-                       global_cache_flush();
+                       readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4));    /* PCI Posting. */
+
                        agp_bridge->driver->tlb_flush(mem);
                        return 0;
                }
@@ -236,14 +243,17 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
        }
 
 insert:
-       global_cache_flush();
+       if (!mem->is_flushed) {
+               global_cache_flush();
+               mem->is_flushed = TRUE;
+       }
+
        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. */
        }
-       global_cache_flush();
+       readl(intel_i810_private.registers+I810_PTE_BASE+((j-1)*4));    /* PCI Posting. */
 
        agp_bridge->driver->tlb_flush(mem);
        return 0;
@@ -254,12 +264,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;
 }
@@ -370,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;
 
@@ -380,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) {
@@ -576,6 +620,9 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int
        int i,j,num_entries;
        void *temp;
 
+       if (mem->page_count == 0)
+               return 0;
+
        temp = agp_bridge->current_size;
        num_entries = A_SIZE_FIX(temp)->num_entries;
 
@@ -598,16 +645,18 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int
                (mem->type != 0 && mem->type != AGP_PHYS_MEMORY))
                return -EINVAL;
 
-       global_cache_flush();   /* FIXME: Necessary ?*/
+       if (!mem->is_flushed) {
+               global_cache_flush();
+               mem->is_flushed = TRUE;
+       }
 
        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. */
        }
+       readl(intel_i830_private.registers+I810_PTE_BASE+((j-1)*4));
 
-       global_cache_flush();
        agp_bridge->driver->tlb_flush(mem);
        return 0;
 }
@@ -617,7 +666,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");
@@ -626,10 +676,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;
 }
@@ -686,6 +735,9 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start,
        int i,j,num_entries;
        void *temp;
 
+       if (mem->page_count == 0)
+               return 0;
+
        temp = agp_bridge->current_size;
        num_entries = A_SIZE_FIX(temp)->num_entries;
 
@@ -708,15 +760,17 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start,
                (mem->type != 0 && mem->type != AGP_PHYS_MEMORY))
                return -EINVAL;
 
-       global_cache_flush();
+       if (!mem->is_flushed) {
+               global_cache_flush();
+               mem->is_flushed = TRUE;
+       }
 
        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. */
        }
+       readl(intel_i830_private.gtt+j-1);
 
-       global_cache_flush();
        agp_bridge->driver->tlb_flush(mem);
        return 0;
 }
@@ -726,7 +780,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");
@@ -735,30 +790,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 = 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.
@@ -821,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;
@@ -1574,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,
@@ -1598,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,
index d73be4c..902648d 100644 (file)
@@ -281,10 +281,11 @@ static int __devinit agp_sgi_init(void)
        else
                return 0;
 
-       sgi_tioca_agp_bridges =
-           (struct agp_bridge_data **)kmalloc(tioca_gart_found *
-                                              sizeof(struct agp_bridge_data *),
-                                              GFP_KERNEL);
+       sgi_tioca_agp_bridges = kmalloc(tioca_gart_found *
+                                       sizeof(struct agp_bridge_data *),
+                                       GFP_KERNEL);
+       if (!sgi_tioca_agp_bridges)
+               return -ENOMEM;
 
        j = 0;
        list_for_each_entry(info, &tioca_list, ca_list) {
index 778e701..f7a416c 100644 (file)
 #define PCI_DEVICE_ID_VIA_3296_0       0x0296
 #define PCI_DEVICE_ID_VIA_8363_0       0x0305
 #define PCI_DEVICE_ID_VIA_P4M800CE     0x0314
+#define PCI_DEVICE_ID_VIA_K8M890CE     0x0336
 #define PCI_DEVICE_ID_VIA_8371_0       0x0391
 #define PCI_DEVICE_ID_VIA_8501_0       0x0501
 #define PCI_DEVICE_ID_VIA_82C561       0x0561