From d5cb8d38cd0029b3573e1c8d5d99d99c86dbdbd6 Mon Sep 17 00:00:00 2001 From: Gabriel Mansi Date: Sat, 16 Dec 2006 20:24:27 -0300 Subject: [AGPGART] K8M890 support for amd-k8. Signed-off-by: Dave Jones --- drivers/char/agp/amd64-agp.c | 9 +++++++++ include/linux/pci_ids.h | 1 + 2 files changed, 10 insertions(+) diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 2f2c4efff8a..979300405c0 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -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), diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 95c1e74afeb..5c87cd8a56f 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1273,6 +1273,7 @@ #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 -- cgit v1.2.3 From 5aa80c72263904f1e52eee8ed8cb75887b1d1dc3 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 20 Dec 2006 16:33:41 +0100 Subject: [AGPGART] Remove unnecessary flushes when inserting and removing pages. This patch is to speed up flipping of pages in and out of the AGP aperture as needed by the new drm memory manager. A number of global cache flushes are removed as well as some PCI posting flushes. The following guidelines have been used: 1) Memory that is only mapped uncached and that has been subject to a global cache flush after the mapping was changed to uncached does not need any more cache flushes. Neither before binding to the aperture nor after unbinding. 2) Only do one PCI posting flush after a sequence of writes modifying page entries in the GATT. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Jones --- drivers/char/agp/generic.c | 11 +++++--- drivers/char/agp/intel-agp.c | 62 ++++++++++++++++++++++++++++++-------------- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 883a36a2783..3491d6f84bc 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -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; } diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 555b3a8ab49..029d7f69756 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -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; } @@ -576,6 +588,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 +613,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 +634,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 +644,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 +703,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 +728,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 +748,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,10 +758,9 @@ 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; } -- cgit v1.2.3 From c41e0deb50c44f9d119c2268f1be05e6a6bb5772 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 19 Dec 2006 12:57:24 -0800 Subject: [AGPGART] fix detection of aperture size versus GTT size on G965 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 Signed-off-by: Andrew Morton Signed-off-by: Dave Jones --- drivers/char/agp/agp.h | 4 ++ drivers/char/agp/intel-agp.c | 110 +++++++++++++++++++++++-------------------- 2 files changed, 62 insertions(+), 52 deletions(-) diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 8b3317fd46c..1d59e2a5b9a 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -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 diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 029d7f69756..ccb8018b831 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -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, -- cgit v1.2.3 From 7f02d687b44aba0cfc393102ea1ccc78eadf8a04 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 27 Dec 2006 13:16:49 +0100 Subject: [AGPGART] Fix PCI-posting flush typo. Unfortunately there was a typo in one of the patches I sent, (The one now committed to the agpgart tree). It may cause a bus error on i810 type hardware. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Jones --- drivers/char/agp/intel-agp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index ccb8018b831..ab0a9c0ad7c 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -253,7 +253,7 @@ insert: mem->memory[i], mem->type), intel_i810_private.registers+I810_PTE_BASE+(j*4)); } - readl(intel_i810_private.registers+I810_PTE_BASE+(j-1*4)); /* PCI Posting. */ + readl(intel_i810_private.registers+I810_PTE_BASE+((j-1)*4)); /* PCI Posting. */ agp_bridge->driver->tlb_flush(mem); return 0; -- cgit v1.2.3 From 7b37b064c294af350c462f77d7a9a44485a93684 Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Tue, 2 Jan 2007 14:44:31 -0800 Subject: [AGPGART] drivers/char/agp/sgi-agp.c: check kmalloc() return value drivers/char/agp/sgi-agp.c: check kmalloc() return value Signed-off-by: Amit Choudhary Signed-off-by: Dave Jones Signed-off-by: Andrew Morton --- drivers/char/agp/sgi-agp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index d73be4c2db8..902648db7ef 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -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) { -- cgit v1.2.3